Documentation Index
Fetch the complete documentation index at: https://mintlify.com/cloudflare/vinext/llms.txt
Use this file to discover all available pages before exploring further.
The next/dynamic module provides SSR-safe dynamic imports with code splitting, loading states, and client-only rendering options.
Import
import dynamic from 'next/dynamic'
Basic Usage
import dynamic from 'next/dynamic'
const DynamicComponent = dynamic(() => import('./HeavyComponent'))
export default function Page() {
return (
<div>
<h1>My Page</h1>
<DynamicComponent />
</div>
)
}
The component is code-split into a separate bundle and loaded on-demand.
API Reference
dynamic
function dynamic<P>(
loader: () => Promise<{ default: ComponentType<P> } | ComponentType<P>>,
options?: DynamicOptions
): ComponentType<P>
loader
() => Promise<Component>
required
Function that returns a dynamic import.dynamic(() => import('./Component'))
dynamic(() => import('./Component').then(mod => mod.NamedExport))
Loading and rendering options.interface DynamicOptions {
loading?: ComponentType<{ error?: Error | null; isLoading?: boolean; pastDelay?: boolean }>
ssr?: boolean
}
Options
loading
Component shown while the dynamic component is loading.
const DynamicChart = dynamic(() => import('./Chart'), {
loading: () => <div>Loading chart...</div>
})
The loading component receives props:
Whether the component is currently loading.
Error if the import failed.const DynamicComponent = dynamic(() => import('./Component'), {
loading: ({ isLoading, error }) => {
if (error) return <div>Failed to load: {error.message}</div>
if (isLoading) return <div>Loading...</div>
return null
}
})
Whether the loading state has been showing long enough (always true in vinext).
ssr
Whether to render the component on the server.
const ClientOnlyComponent = dynamic(() => import('./ClientOnly'), {
ssr: false
})
When ssr: false:
- Server: Renders the loading component (or nothing)
- Client: Loads and renders the component after hydration
Useful for components that depend on browser APIs:
const Map = dynamic(() => import('./LeafletMap'), {
ssr: false,
loading: () => <div>Loading map...</div>
})
Examples
With Named Export
import dynamic from 'next/dynamic'
const DynamicEditor = dynamic(
() => import('./Editor').then(mod => mod.Editor)
)
With Loading State
import dynamic from 'next/dynamic'
function LoadingSpinner() {
return (
<div className="flex justify-center p-4">
<div className="animate-spin rounded-full h-8 w-8 border-b-2" />
</div>
)
}
const DynamicComponent = dynamic(
() => import('./HeavyComponent'),
{ loading: LoadingSpinner }
)
Client-Only Component
import dynamic from 'next/dynamic'
const DynamicChart = dynamic(
() => import('./Chart'),
{
ssr: false,
loading: () => <div>Initializing chart...</div>
}
)
export default function Analytics() {
return (
<div>
<h1>Analytics Dashboard</h1>
<DynamicChart data={data} />
</div>
)
}
Multiple Dynamic Components
import dynamic from 'next/dynamic'
const Header = dynamic(() => import('./Header'))
const Sidebar = dynamic(() => import('./Sidebar'))
const Content = dynamic(() => import('./Content'))
export default function Layout({ children }) {
return (
<div>
<Header />
<div className="flex">
<Sidebar />
<Content>{children}</Content>
</div>
</div>
)
}
Error Handling
import dynamic from 'next/dynamic'
const DynamicComponent = dynamic(
() => import('./Component'),
{
loading: ({ error, isLoading }) => {
if (error) {
console.error('Failed to load component:', error)
return (
<div className="error">
<p>Failed to load component</p>
<button onClick={() => window.location.reload()}>
Retry
</button>
</div>
)
}
if (isLoading) {
return <div>Loading...</div>
}
return null
}
}
)
How It Works
Server-Side (SSR Enabled)
vinext uses React.lazy with Suspense:
const LazyComponent = React.lazy(() => import('./Component'))
function DynamicWrapper(props) {
return (
<Suspense fallback={<LoadingComponent />}>
<LazyComponent {...props} />
</Suspense>
)
}
renderToReadableStream suspends until the dynamic component loads.
Client-Side
Standard React.lazy for code splitting:
const LazyComponent = React.lazy(() => import('./Component'))
<Suspense fallback={<Loading />}>
<LazyComponent />
</Suspense>
Vite automatically creates separate chunks for dynamic imports.
SSR: false
Server: Renders loading state or nothing
Client: Uses useEffect to detect mount, then loads the component:
function ClientOnly(props) {
const [mounted, setMounted] = useState(false)
useEffect(() => setMounted(true), [])
if (!mounted) return <Loading />
return <LazyComponent {...props} />
}
Use Cases
Heavy Third-Party Libraries
// Chart.js is 200KB — don't load it on every page
const Chart = dynamic(() => import('react-chartjs-2').then(m => m.Chart), {
ssr: false
})
Admin Panels
// Only load admin UI when needed
const AdminPanel = dynamic(() => import('./AdminPanel'), {
loading: () => <div>Loading admin panel...</div>
})
export default function AdminPage() {
const { isAdmin } = useUser()
if (!isAdmin) return <div>Access denied</div>
return <AdminPanel />
}
Modal Dialogs
const Modal = dynamic(() => import('./Modal'))
export default function Page() {
const [isOpen, setIsOpen] = useState(false)
return (
<div>
<button onClick={() => setIsOpen(true)}>Open Modal</button>
{isOpen && <Modal onClose={() => setIsOpen(false)} />}
</div>
)
}
Browser-Only Features
// Geolocation, Canvas, WebGL, etc.
const MapComponent = dynamic(() => import('./Map'), {
ssr: false,
loading: () => <div>Loading map...</div>
})
Limitations
Top-level only: dynamic() must be called at the module level, not inside components or conditionals.
// ✅ Correct
const DynamicComponent = dynamic(() => import('./Component'))
function Page() {
return <DynamicComponent />
}
// ❌ Wrong
function Page() {
const DynamicComponent = dynamic(() => import('./Component'))
return <DynamicComponent />
}
No server-side props: Dynamic components cannot receive props from getServerSideProps in the traditional sense. Pass props explicitly.
Loading flicker: With ssr: false, the client always shows the loading state first (even if hydrating), causing a brief flicker.
Comparison with React.lazy
vinext’s dynamic is a thin wrapper around React.lazy + Suspense:
| Feature | dynamic | React.lazy |
|---|
| Code splitting | ✅ | ✅ |
| SSR support | ✅ | ❌ |
| Loading state | ✅ | Manual |
| Error handling | ✅ | Manual |
ssr: false | ✅ | Manual |
Source
View source code →
Implementation: /home/daytona/workspace/source/packages/vinext/src/shims/dynamic.ts