Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/vercel/next.js/llms.txt

Use this file to discover all available pages before exploring further.

Lazy loading in Next.js helps reduce the initial JavaScript bundle by deferring the load of components and libraries until they’re needed. There are two main approaches:
  1. dynamic() from next/dynamic — the primary API for lazy loading in the App Router.
  2. React.lazy() with Suspense — works in Client Components.

dynamic()

next/dynamic is a combination of React.lazy() and Suspense. It works in both Server and Client Components.

Basic usage

import dynamic from 'next/dynamic'

const DynamicComponent = dynamic(() => import('./heavy-component'))

export default function Page() {
  return (
    <div>
      <DynamicComponent />
    </div>
  )
}

Loading UI

Show a fallback while the component loads:
import dynamic from 'next/dynamic'

const DynamicComponent = dynamic(
  () => import('./heavy-component'),
  {
    loading: () => <p>Loading...</p>,
  }
)

export default function Page() {
  return <DynamicComponent />
}

Disabling SSR

To prevent a component from rendering on the server, use ssr: false. This is useful for components that depend on browser APIs:
'use client'

import dynamic from 'next/dynamic'

const DynamicComponent = dynamic(
  () => import('./browser-only-component'),
  { ssr: false }
)

export default function Page() {
  return <DynamicComponent />
}
Using ssr: false prevents any server-rendered HTML for that component. Use only when necessary, such as for components that access window or other browser-only globals.

Named exports

To lazy load a named export from a module, return it from the Promise returned by the dynamic import:
import dynamic from 'next/dynamic'

const DynamicChart = dynamic(() =>
  import('./charts').then((mod) => mod.BarChart)
)

export default function Page() {
  return <DynamicChart />
}

Lazy loading libraries

Third-party libraries can also be loaded on demand using import() inside an event handler:
app/page.tsx
'use client'

import { useState } from 'react'

export default function Page() {
  const [results, setResults] = useState(null)

  const handleSearch = async (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault()
    const { default: Fuse } = await import('fuse.js')
    const fuse = new Fuse(['item1', 'item2', 'item3'])
    const result = fuse.search('item')
    setResults(result)
  }

  return (
    <form onSubmit={handleSearch}>
      <button type="submit">Search</button>
      {results && <pre>{JSON.stringify(results, null, 2)}</pre>}
    </form>
  )
}

React.lazy() with Suspense

Inside Client Components, you can use React.lazy() and Suspense directly:
app/page.tsx
'use client'

import { lazy, Suspense } from 'react'

const DynamicComponent = lazy(() => import('./heavy-component'))

export default function Page() {
  return (
    <Suspense fallback={<p>Loading...</p>}>
      <DynamicComponent />
    </Suspense>
  )
}
dynamic() from next/dynamic supports additional options like ssr: false that React.lazy() does not. Prefer dynamic() for full Next.js feature support.

dynamic() options reference

loader
function
required
A function that returns a Promise resolving to the component module. Usually an import() call.
dynamic(() => import('./my-component'))
loading
function
A component to render while the dynamic component is loading.
{ loading: () => <Skeleton /> }
ssr
boolean
default:"true"
Whether to server-side render the component. Set to false to skip SSR for browser-only components.