next/dynamic is a Next.js wrapper around React.lazy and Suspense that extends them with framework-specific features like SSR control, named export support, and server-side compatibility in Server Components
Next.js's next/dynamic builds upon React's native lazy loading primitives (React.lazy and Suspense) but adds critical framework-specific functionality. While React.lazy is limited to client-side execution and requires default exports, next/dynamic provides server-side rendering control, named export support, and importantly, works seamlessly inside React Server Components [citation:2]. The official documentation describes it as a 'composite of React.lazy and Suspense,' but in practice, it's a more powerful abstraction tailored for Next.js's hybrid rendering model [citation:2][citation:1].
Server Component support: React.lazy cannot be used in Server Components and will throw an error; next/dynamic works perfectly in Server Components for conditional client component loading [citation:8]
SSR control: next/dynamic provides the ssr: false option to completely disable server-side rendering, which React.lazy cannot do [citation:2][citation:4]
Named exports: React.lazy only works with default exports; next/dynamic allows importing named exports via a then() callback [citation:2][citation:9]
Built-in loading UI: next/dynamic includes a loading option that renders a placeholder during import, while React.lazy requires a separate Suspense boundary [citation:1][citation:4]
Preloading: next/dynamic automatically handles preloading optimizations that must be manually implemented with React.lazy [citation:2]
React's native lazy loading mechanism consists of two complementary APIs: React.lazy() for component code splitting and Suspense for handling loading states. React.lazy() accepts a function that returns a dynamic import promise, which must resolve to a module with a default export [citation:3][citation:5]. The loaded component must be wrapped in a Suspense boundary that provides a fallback UI during loading [citation:7][citation:10]. This combination is perfect for client-side React applications but has significant limitations in Next.js: it cannot be used in Server Components, offers no server-side rendering control, and only works with default exports [citation:8].
Path requirement: In next/dynamic, the import path must be a string literal, not a variable or template string, to enable proper webpack bundling [citation:2]
Double loading states: If your dynamically imported component also fetches data with Suspense-enabled libraries, you'll see two separate loading UIs unless you coordinate the fallbacks [citation:1]
Suspense in Server Components: Suspense works in Server Components for async operations, but not with React.lazy—use next/dynamic instead [citation:8]
Default SSR behavior: By default, next/dynamic attempts server-side rendering; set ssr: false explicitly for client-only components [citation:2][citation:4]