---
title: "Next.js Performance Optimizations I Have Applied Over the Years"
description: "A summary of more than two years of Next.js development experience, covering 13 practical performance optimization techniques including image optimization, bundle slimming, CSS reduction, CDN-served static assets, and SSG/ISR rendering strategies."
canonical_url: "https://blog.markkulab.net/en/post/enhance-nextjs-performance"
author: "Mark Ku"
author_url: "https://blog.markkulab.net/en/author/mark-ku"
site: "Mark Ku's Tech Notes"
date_published: "2024-10-10 20:01:01 +0800"
category: "Frontend"
tags: ["nextjs", "react", "performance", "image optimization", "bundle size", "ssr", "cdn", "cloudflare"]
language: "en"
license: "CC BY 4.0"
license_url: "https://creativecommons.org/licenses/by/4.0/"
attribution: "when reusing or quoting, credit the author and link back to the original"
---

# Next.js Performance Optimizations I Have Applied Over the Years

## 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.tsx` or 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-analyzer` to 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.)
### 8. Tune transport and compression protocols (Brotli), and enable HTTP/2 and HTTP/3 for faster delivery and better compression efficiency.
### 9. Reduce request count and shrink API responses. Cache backend data that rarely changes but is queried frequently.
### 10. Server rendering is expensive. Where possible, use SSG or ISR; pages that do not need pre-rendering can be CSR. When rendering, prefer reading from Redis over hitting the API — Redis is always faster.
### 11. Use an LTM and multiple machines/instances to spread the load.
### 12. Upgrade to the App Router and use server components, so non-interactive components do not get bundled into client-side JS.
### 13. Upgrade Next.js regularly. Each release claims performance improvements, and while every upgrade brings minor pain, skipping upgrades for too long makes future upgrades much harder.

---

## About this article and its author

Originally published on [Mark Ku's Tech Notes](https://blog.markkulab.net/en/post/enhance-nextjs-performance)

License: [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/) — when reusing or quoting, credit the author and link back to the original

### About the author

**[Mark Ku](https://blog.markkulab.net/en/author/mark-ku)** — Software Solution Provider

- 10+ years senior software engineer, now an AI Builder
- Focused on large-platform architecture — North-American e-commerce, AI SaaS subscription billing
- Combining AI Agents and automation to build evolvable product foundations

### Free tools built by the author

All of these are free to use:

- [Free PDF Sign Tool](https://blog.markkulab.net/en/tools/pdf-sign): Online PDF sign tool — draw, type, or upload a signature, then drag, resize, and download. Everything runs in your browser; nothing is uploaded.
- [VS Code Refactory](https://blog.markkulab.net/en/tools/refactory): Refactory is a VS Code refactoring extension: 34 actions plus a 37-rule code-smell inspection layer with a Code Health dashboard, across 18 languages, backed by 534 tests. It learns your repo's conventions: where interfaces live, where DI is registered, whether 'use client' belongs. It ranks files by git churn × complexity so you know what to fix first, and hands any smell to the Claude Code already on your machine. Free to use, and your source never leaves your computer.
- [DB-Kit Database Manager](https://blog.markkulab.net/en/tools/db-kit): DB-Kit is a lightweight, cross-platform database manager built with Tauri + Rust + React. Manage MySQL, MariaDB, PostgreSQL, SQL Server, Oracle, SQLite, MongoDB, Redis, Kafka, Elasticsearch and RabbitMQ from one consistent interface: passwords encrypted in the OS keychain, SSH tunnels, full CRUD, a visual query builder, stacked multi-statement result sets, cross-connection data transfer and compare/sync, Excel / CSV import & export, visualized execution plans, ER diagrams, scheduled backups, SQL stress testing with p50–p99 latency percentiles, a 15-rule SQL review engine, Kafka message browsing with monitoring & alerts, a bilingual UI (Traditional Chinese / English), a built-in AI assistant (natural-language SQL, AI review and tuning advice) and the dbk CLI. Free and open source (MIT), with installers for Windows, macOS and Linux.
- [VS Code Super Mermaid](https://blog.markkulab.net/en/tools/super-mermaid): Super Mermaid is a VS Code extension for beautiful Mermaid diagrams out of the box: auto-colored live preview, mouse pan & zoom, high-res PNG / SVG export, 21 templates and multiple themes. Free and open source (MIT).
- [React Super Mermaid](https://blog.markkulab.net/en/tools/react-super-mermaid): react-super-mermaid is an open-source React component library: render beautiful Mermaid diagrams with a single <MermaidViewer>, with built-in colorful / sketch themes, pan & zoom, in-diagram search, and high-res SVG / PNG export. Lightweight, SSR-safe, fully typed. Free and open source (MIT).
- [Jira / Confluence Super Mermaid](https://blog.markkulab.net/en/tools/jira-super-mermaid): An Atlassian Forge app: write Mermaid syntax directly inside a Jira issue or a Confluence page and get flowcharts, sequence diagrams, state machines and Gantt charts. 11 diagram types, SVG / PNG export, light and dark themes, full CJK support. Runs on Atlassian: your diagrams live in your own site and the app calls no third-party service. Free, coming soon to the Atlassian Marketplace.
- [Mermaid Live Preview](https://blog.markkulab.net/en/tools/mermaid-preview): Write Mermaid in your browser, see it render instantly, and share the whole diagram as a single link. No sign-up, nothing uploaded to a server, and mermaid.live share links work as-is.
- [React Intl Phone Number](https://blog.markkulab.net/en/tools/react-intl-phone-number): react-intl-phone-number is an open-source React component: framework-agnostic and antd-free, with E.164 in/out, a searchable flag / country-code dropdown, configurable validation levels (strict / mobile-strict / loose), themeable CSS, and i18n — phone logic powered by google-libphonenumber. Lightweight and fully typed. Free and open source (MIT).
- [Uptime Kuma Cluster](https://blog.markkulab.net/en/tools/uptime-kuma-cluster): Turn single-node Uptime Kuma into a highly available cluster: OpenResty + Lua smart load balancing, shared MariaDB state, health checks and automatic failover, plus cluster-management REST APIs. One Docker Compose command to start. Free and open source (MIT).
- [Special Education](https://blog.markkulab.net/en/education): Learning materials crafted for special education students

### Daily podcasts

- [Mark's Tech Insights — Daily AI News](https://blog.markkulab.net/en/category/tech-news): Daily curated AI and tech trends. Catch the latest developments via audio summaries — covering AI applications, software architecture, DevOps, and engineering practice. — RSS: https://blog.markkulab.net/feed.xml
- [AI股市蝦聊](https://blog.markkulab.net/en/category/ai-stock-chat): Every trading day, an AI-analyzed take on the Taiwan stock market, delivered as a two-host conversation covering the session and the next-day outlook. — RSS: https://blog.markkulab.net/ai-stock-chat/feed.xml
- [開源好物週報](https://blog.markkulab.net/en/category/open-source-weekly): A weekly two-host pick of free open-source tools surfaced from real Hacker News, GitHub, and Reddit buzz — what pain they solve and the fastest way to get started. — RSS: https://blog.markkulab.net/open-source-weekly/feed.xml

### Newsletter

[Subscribe to the newsletter](https://blog.markkulab.net/en/subscribe) — Be the first to know about new posts. No spam, unsubscribe anytime.
