Introduction
After working with the Next.js framework for over two years, I figured it was time to put together a list of the performance optimizations we have applied. Next.js itself does a lot of work to optimize JavaScript builds and images.
1. Image optimization
- Next.js already does plenty out of the box: lazy loading, image-loader optimizations (resizing, format conversion, quality compression), and serving different sizes based on the user's resolution. Just by using next/image correctly, you get image optimization for free.
- Move images to a CDN, and switch the Next.js loader to a third-party image loader.
2. Reduce JS size and shrink the bundle
- Next.js does code splitting automatically. Anything used in the shared
_app.tsxor layout ends up in the main JS bundle. Move it down to subpages so it does not get bundled into the main JS. - Pages should only render the components they actually need. Use dynamic import for components only used by the current page so they are not bundled into the main JS.
import dynamic from 'next/dynamic';
const CartView = dynamic(() => import('./cartView'));
- On the server side, only fetch the data the page needs and avoid sending unnecessary data to the client.
- Use
next/bundle-analyzerto identify oversized packages, and replace them with lighter alternatives, e.g. Moment.js to Day.js. - The way you import packages also impacts the bundle size, e.g. lodash:
import throttle from 'lodash/throttle'; // good
import { throttle } from 'lodash'; // bad
- JS or CSS that is not required for the initial render should be loaded on demand to avoid blocking the first render. The shopping cart side panel is a good example.
3. Reduce CSS size.
- Move shared CSS that is not needed on every page into individual pages or components, and remove unused CSS.
- Replace heavyweight CSS frameworks such as Bootstrap.
4. Use Jenkins to push static files to a CDN. The CDN reduces I/O load on the origin server, and you can enable client-side caching at the CDN edge.
5. Reduce layout shift and jitter during page rendering, since Google penalizes this.
6. Apply font-display: swap so a fallback font is shown while the web font is loading.
7. Audit and remove unused third-party JS. JS that is only required after user interaction can be loaded later, avoiding loading too much JS during the first render and blocking the main thread.
<Script
src="https://applepay.cdn-apple.com/jsapi/v1/apple-pay-sdk.js"
strategy="afterInteractive"
></Script>
(Loading JS only after the user scrolls would likely be even better, but it depends on the requirement.)




























Comments