Optimisaton Tools
Code Splitting
Code splitting is the practice of breaking up your JavaScript into smaller chunks, which can be loaded on demand. This helps improve the initial load time by only loading the necessary code for the current page.
Next.js automatically splits your code of into separate bundles for each page (using Page Router) or for every Server Component (for App Router), reducing the amount of JavaScript that needs to be loaded initially.
You can use dynamic imports to load components only when they are needed. There are to ways to achieve this:
- Using dynamic imports with
next/dynamic - Using
React.lazy()withSuspense
import dynamic from 'next/dynamic';
const DynamicComponent = dynamic(() =>
import('../components/DynamicComponent')
);
const AdditionalComponent = dynamic(() =>
import('../components/ConditionalComponent')
);
export default function Componets({ showMore }) {
return (
<>
{/* Load immediately, but in a separate client bundle */}
<DynamicComponent />;{/* Load on demand, only if `showMore` prop is true */}
{showMore && <AdditionalComponent />}
</>
);
}
Lazy Loads on Client Side
When using React.lazy() and Suspense, Client Components will be pre-rendered (SSR) by default.
If you want to disable pre-rendering for a Client Component, you can use the ssr option set to false:
const ComponentC = dynamic(() => import('../components/C'), { ssr: false });
Loading External Libraries
External libraries can be loaded on demand using the import() function.
In this
exapmle,
the module fuse.js is only loaded on the client after the user types in the
search input.
'use client';
import { useState } from 'react';
const names = ['Tim', 'Joe', 'Bel', 'Lee'];
export default function Page() {
const [results, setResults] = useState();
return (
<div>
<input
type="text"
placeholder="Search"
onChange={async (e) => {
const { value } = e.currentTarget;
// Dynamically load fuse.js
const Fuse = (await import('fuse.js')).default;
const fuse = new Fuse(names);
setResults(fuse.search(value));
}}
/>
<pre>Results: {JSON.stringify(results, null, 2)}</pre>
</div>
);
}
Image Optimization
The next/image module automatically optimizes images on demand, providing
features like lazy loading, resizing, and serving modern formats like WebP.
-
srccontains the link to the image file. The image source can be eiter a local file (statically imported) or a remote resource (URL). The module supports.jpg,.png, and.webpformats. -
widthandheightproperties allows a browser to allocate the necessary space in the layout before the image loads. Next.js can determite properties automatically for statically imported images. For remote images you need to specify them explicitly, because Next.js does not have access to them. -
fillproperty indicates that image fills the parent container. Withfill, we don't need to specifywidthandheight -
placeholderis an optional property that specifies the content that will be displayed until the original file is downloaded.- When
empty, the image container will be empty - When
blur, the container will be filled by blurred image. If the image is statically imported, the blurred version will be generated automatically. Otherwise, you should provide it usingblurDataUrlproperty. - When
data:image/..., the providedData URLwill be user as the placeholder.
- When
The priority prop gives the image a higher loading priority. This means the
browser will start loading it sooner, even before other lower-priority
resources.
This is useful for above-the-fold images (hero images or key visual elements). It's recommended to use this property with the images detected as the Largest Contentful Paint (LCP) elements.
import Image from 'next/image';
export default function HomePage() {
return (
<div>
<h1>Welcome to the Home Page</h1>
<Image
src="/path/to/important-image.jpg"
width={800}
height={600}
alt="Important description"
priority
/>
<p>Other content on the page...</p>
<Image
src="/path/to/image.jpg"
width={300}
height={300}
alt="Description"
/>
</div>
);
}
Font Optimization
The next/font module allows you to load and optimize fonts from Google Fonts
or local sources with built-in support for optimizing font loading and reducing
layout shifts.
Fonts imported by next/font are self-hosted. This means that the files are
stored on your server, and the browser requests them from the same domain as
your deployment, rather than from external services such as Google Fonts.
import { GoogleFont } from 'next/font/google';
const roboto = GoogleFont({
name: 'Roboto',
weights: ['400', '700'],
styles: ['normal', 'italic'],
});
export default function HomePage() {
return (
<div className={roboto.className}>
<p>Hello, world!</p>
</div>
);
}
Script Optimization
The next/script module helps you optimize loading third-party scripts. You can
control how and when scripts are loaded using strategies like
beforeInteractive, afterInteractive, and lazyOnload.
import Script from 'next/script';
export default function HomePage() {
return (
<>
<Script src="https://example.com/script.js" strategy="lazyOnload" />
<p>Content</p>
</>
);
}
Strategies
Strategy next/script loads third-party scripts on any page or layout by default. However, you can customise its behaviour via the strategy property:
-
beforeInteractive: Loads the script before any Next.js code and before any page hydration occurs. -
afterInteractive: (default) Loads the script earlier, but after some some hydration on the page occurs. -
lazyOnload: Loads the script later while the browser is idle. -
worker: Loads the script in web worker.
import Script from 'next/script';
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body>
{children}
<Script
src="https://example.com/script.js"
strategy="beforeInteractive"
/>
</body>
</html>
);
}