DriversRecommendedOutdated drivers can make a good PC feel brokenScan driver issues before chasing fixes manually.Scan NowOctober DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsClean PCRecommendedOne scan can reveal what keeps slowing WindowsLook for cleanup and repair opportunities.Run Scan×
Skip to content
JavaScript

How to Implement Lazy Loading in Next.js

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

For components in Next.js, use next/dynamic or React.lazy() with Suspense; for a large library, use native import() when the user needs it; for images, use next/image, which lazy-loads by default. Keep dynamic imports explicit and at module scope. Set ssr: false only for a Client Component that cannot render without browser APIs.

What lazy loading does in Next.js

Lazy loading defers downloading or rendering work until it is needed, reducing the JavaScript required for a route’s initial render. It is chiefly useful for Client Components and libraries that are not needed immediately. Server Components are automatically code split, so adding a separate lazy-loading wrapper to every Server Component is usually unnecessary.

The right technique depends on what you are deferring and when it is needed:

  • A component needed during the route’s initial render: use next/dynamic or React.lazy() with a Suspense boundary.
  • A component needed only after an interaction: conditionally render a dynamic component, or import a library inside the event-driven code.
  • A browser-only component: use next/dynamic with {"ssr": false} from a Client Component.
  • An image below the fold: use next/image and leave its default lazy loading in place.

Lazy loading does not guarantee a particular speed improvement. Measure the actual route and bundle before and after a change; the Next.js guides do not publish a universal performance percentage for these patterns.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Lazy-load a component with next/dynamic

next/dynamic is the Next.js convenience API for dynamically importing a component. It can display a loading fallback while the chunk loads. In the App Router, put the directive 'use client' at the top of the file when the component using this API needs to be a Client Component.

'use client'

import dynamic from 'next/dynamic'

const Chart = dynamic(() => import('../components/Chart'), {
  loading: () => <p>Loading chart…</p>,
})

export default function Dashboard() {
  return <Chart />
}

Adjust the import path to the component’s real location. Keep the call to dynamic() at module scope rather than inside the page component. The import must be a literal path inside the dynamic call, not a variable or template string. This gives Next.js the information it needs to associate the call with a bundle and preload it appropriately.

Defer a component until a condition is met

If a panel or modal is not needed until a user action, combine a dynamic import with conditional rendering:

'use client'

import { useState } from 'react'
import dynamic from 'next/dynamic'

const Modal = dynamic(() => import('../components/Modal'), {
  loading: () => <p>Loading dialog…</p>,
})

export default function Page() {
  const [showModal, setShowModal] = useState(false)

  return (
    <>
      <button onClick={() => setShowModal(true)}>Open details</button>
      {showModal ? <Modal /> : null}
    </>
  )
}

The explicit import remains at module scope, while the component itself is not rendered until the condition is true. This avoids initializing the modal as part of the initial render. Provide a fallback if users might notice the delay after opening it.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use React.lazy and Suspense when appropriate

React’s lazy() can defer a component import, and Suspense supplies the fallback. This is a supported option alongside next/dynamic. Use a literal import path and place the lazy declaration outside the component function so it is stable across renders.

'use client'

import { lazy, Suspense } from 'react'

const Chart = lazy(() => import('../components/Chart'))

export default function Dashboard() {
  return (
    <Suspense fallback={<p>Loading chart…</p>}>
      <Chart />
    </Suspense>
  )
}

Choose between this and next/dynamic based on the behavior you need and the surrounding Next.js code. next/dynamic accepts its own loading option and supports the Next.js-specific ssr option. React’s lazy() relies on a Suspense boundary for its pending state.

Disable server rendering for browser-only components

A component that accesses window, document, or another browser-only API during module evaluation or rendering cannot safely run on the server. Load it with next/dynamic and ssr: false from a Client Component:

'use client'

import dynamic from 'next/dynamic'

const Map = dynamic(() => import('../components/Map'), {
  ssr: false,
  loading: () => <p>Loading map…</p>,
})

export default function LocationPanel() {
  return <Map />
}

ssr: false is not supported in a Server Component. If the dynamic declaration currently lives in a Server Component, move that declaration into a Client Component and render the client wrapper from the server-rendered tree. Do not disable SSR by default: components that can render on the server do not need this workaround, and turning off SSR changes what is available in the initial HTML.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Load a library only after user input

For a large dependency used only in a particular interaction, native dynamic import() can postpone loading it until that interaction occurs. For example, the Next.js guide demonstrates loading Fuse.js when a user searches:

'use client'

async function search(value: string) {
  const Fuse = (await import('fuse.js')).default
  const fuse = new Fuse(items, { keys: ['name'] })
  return fuse.search(value)
}

This example assumes items is available in the surrounding component or module. In a real input handler, avoid importing the library on every keystroke: cache the imported module or initialize the search instance once, then reuse it as appropriate. The key distinction is trigger timing: the library is not requested until the search path runs. If the operation can be triggered rapidly, handle overlapping requests and stale results in your component logic.

Show useful loading feedback

A fallback should match the space and purpose of the deferred content. A short text label can be sufficient for a small widget; a chart or map may benefit from a placeholder with a stable height so the surrounding layout does not jump when it appears. Avoid a fallback that implies completion before the content is ready.

Component fallback

With next/dynamic, pass a loading component in the options object. With React lazy(), wrap the component in <Suspense fallback={...}>. Ensure a boundary is present around the lazy component so there is a defined pending state.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Route-segment loading UI

For App Router route segments, add app/segment/loading.tsx. Next.js treats this convention as an instant streamed fallback and swaps in the new content when it is ready. See the Next.js loading.js file convention. This is route-level feedback; it does not replace a component-level fallback when a particular widget needs its own loading presentation.

Lazy-load images with next/image

Use Next.js’s Image component for images. Its loading option defaults to "lazy", so images near the viewport are ordinarily fetched as they approach it without an explicit prop:

import Image from 'next/image'

export default function ArticleImage() {
  return (
    <Image
      src="/hero.jpg"
      alt="A view of the coastline"
      width={1200}
      height={800}
    />
  )
}

You may set loading="lazy" explicitly if it makes the intent clearer, but it is the default. For an image that must load immediately, loading="eager" requests eager loading. Use eager loading or preload selectively for above-the-fold content; making every image eager can work against the goal of deferring offscreen requests. The Next.js Image API reference also notes that native lazy loading may fall back to eager loading in browsers older than Safari 15.4.

Choose the technique by target and trigger

Target When to load Technique Important constraint
Component When rendered next/dynamic with loading, or React lazy() with Suspense Declare an explicit dynamic import at module scope.
Component After a condition or interaction Conditional rendering of a next/dynamic component The condition controls rendering; keep the import declaration static and explicit.
Browser-only component Client-side only next/dynamic with ssr: false Must be declared from a Client Component.
Imported library After an action such as search Native import() in the relevant code path Manage repeated calls and results in application code.
Image As it nears the viewport next/image default loading behavior Reserve eager loading for content that needs to appear immediately.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Measure the result instead of assuming a speedup

Lazy loading trades initial work for work later. It can reduce JavaScript needed on the first route render, but a user may wait when opening a deferred panel, and a late-loaded asset can affect the experience if it is needed immediately. Check the route’s bundle and performance behavior before and after the change with the tools used in your project. Compare equivalent builds and routes, and confirm that the deferred chunk is fetched at the intended point. The official guidance does not establish a fixed percentage improvement for these examples.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

For screenshots used to inspect a rendered route or document visual changes, ScreenshotNeo is a website screenshot API and MCP server for developers. It does not replace bundle or runtime performance measurement.

Troubleshoot common lazy-loading problems

  • The component is still included in the initial route work: check that the import is inside the dynamic() call, that the call is at module scope, and that the path is explicit rather than assembled from a variable. Confirm that the component is not also imported statically elsewhere.
  • ssr: false causes an error: the option is not supported in Server Components. Put the dynamic declaration in a Client Component and render that wrapper where needed.
  • A browser-only component throws a reference error: it may access window or document before client-side rendering. Use a client-only dynamic import when it truly cannot render on the server; otherwise move browser access into an appropriate client-side lifecycle or interaction.
  • The component appears with no pending indicator: add the loading option to next/dynamic, or place a Suspense boundary around a React lazy component.
  • An image loads immediately: inspect whether loading="eager" or a preload setting is present. Remove eager behavior from below-the-fold imagery if it is not needed.
  • An image does not defer in an older browser: Next.js documents that native lazy loading can fall back to eager behavior in browsers older than Safari 15.4; do not treat that browser case as proof that the component code is wrong.
  • Dynamic content is blank or delayed after interaction: verify the condition that renders it, confirm the import path resolves, and inspect the browser’s network and console output for a failed chunk request. Keep a visible fallback and handle failures in the surrounding UI where the app requires recovery.
  • A library appears to load repeatedly: move repeated initialization out of the per-keystroke path or cache the imported module and instance where appropriate. Preserve the intended behavior when inputs change.

Or skip the browser setup

For a rendered-page screenshot, ScreenshotNeo can return an image or PDF from one GET request. Its cleanup can accept cookie/consent banners and remove more than 60 known consent platforms, newsletter popups, and chat widgets before capture; each cleanup step can be turned off. Bot checks/CAPTCHAs, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers identify the page verdict and billing status. It also provides an MCP server for AI agents and has a free allowance of 1,000 screenshots per month without a card; paid plans start at $5 for 3,000 shots.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

See the ScreenshotNeo API documentation for request options. Sign up for 1,000 free screenshots a month with no card.

Frequently Asked Questions

Does Next.js lazy-load images by default?

Yes. The Next.js Image component defaults to native lazy loading; use eager loading selectively for images that need to appear immediately.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Can I use ssr: false in a Server Component?

No. Declare the dynamic component with ssr: false inside a Client Component.

Is there a guaranteed percentage improvement from lazy loading?

No universal figure is established for these patterns. Measure the route and bundle in your own application.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Read next

Recommended PC Tool
Recommended PC Tool
Windows Errors? Fix Them Before They SpreadFree repair scan
Crashes, No Sound, or Screen Glitches?Free driver scan

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.