DEV Community

Cover image for Next.js Client‑Side Rendering: Bundles, Performance & Practical Optimisations
Md Enayetur Rahman
Md Enayetur Rahman

Posted on

Next.js Client‑Side Rendering: Bundles, Performance & Practical Optimisations

This article is part of my Learning Patterns series, where I distill insights from Lydia Hallie & Addy Osmani’s book into real‑world React/Next.js workflows.


1  |  What is Client‑Side Rendering (CSR)?

In CSR, the server ships only a bare‑bones HTML container; React and its JavaScript take over in the browser—handling routing, data fetching and templating.

Server ⟶ <div id="root"></div>  
Browser ⟶ downloads `/static/js/bundle.js` ⟶ runs React ⟶ paints UI
Enter fullscreen mode Exit fullscreen mode

Quick demo in a Next.js 14 app

// app/csr-clock/page.js
"use client";
import { useEffect, useState } from "react";

export default function Clock() {
  const [now, setNow] = useState(Date.now());
  useEffect(() => {
    const id = setInterval(() => setNow(Date.now()), 1000);
    return () => clearInterval(id);
  }, []);
  return <p className="text-center text-2xl">{new Date(now).toLocaleTimeString()}</p>;
}
Enter fullscreen mode Exit fullscreen mode

Everything (including the interval) runs on the client, so no extra round‑trips are needed.


2  |  Understanding the JavaScript Bundle

What lands in the bundle?

  • Static imports in every route.
  • Third‑party dependencies.
  • Your own components and utilities.

The book reminds us that “the bigger the bundle, the longer users stare at a blank screen” before FCP and TTI kick in.

Peeking inside

# Install once
npm i -D @next/bundle-analyzer
# Build with analysis
ANALYZE=true npm run build
Enter fullscreen mode Exit fullscreen mode

This opens an interactive treemap showing which packages bloat the bundle.

Measuring real performance

# Local Lighthouse
npx lighthouse http://localhost:3000 --view

# Web‑Vitals snippet (in _app.tsx)
import { reportWebVitals } from 'next/web-vitals';
export function reportWebVitals(metric) {
  console.log(metric);
}
Enter fullscreen mode Exit fullscreen mode

3  |  Pros & Cons of CSR

| 💚 Strengths | 😬 Trade‑offs |
| --------------------------------------------------------------| --------------- -------------------------------------------------|
| SPA‑like fluid navigation—no full page reloads | Initial blank screen until JS downloads & executes |
| Clear separation between API & UI layers | SEO is tougher: crawlers may time‑out before content appears |
| Powerful client‑only interactions (e.g. real‑time dashboards) | Large bundles hit FCP/LCP/TTI, especially on low‑end devices |
| Works offline/with service‑workers | Potential duplication of validation logic across client & server |


4  |  Five Ways to Speed‑Up CSR in Next.js

Performance is inversely proportional to bundle size—so shrink, split and delay JS!

4.1 Route‑based code splitting (automatic)

Next.js ships each page as its own chunk. Avoid giant layouts that re‑import heavy libs everywhere.

4.2 Component‑level code splitting

import dynamic from "next/dynamic";

const EmojiPicker = dynamic(() => import("./EmojiPicker"), {
  ssr: false,
  loading: () => <p>Loading…</p>,
});
Enter fullscreen mode Exit fullscreen mode

EmojiPicker drops out of the initial bundle and loads on demand.

4.3 Tree‑shaking & dead‑code elimination

  • Use ES modules (import { X } from "y")
  • Prefer lightweight icon/lib alternatives (e.g. @svgr/webpack over Font‑Awesome).

4.4 Inline critical CSS, defer the rest

Inline the bare minimum styles needed for first paint—defer bulky component CSS with @import() inside the component file.

4.5 Audit third‑party packages

Regularly compare alternatives (react-selectreact-select-search, etc.) and watch Lighthouse/TBT drop.

Real‑world win (Next.js Movies App)

  • Lazy‑loading a sidebar reduced Total Blocking Time by 71%.
  • Swapping Font‑Awesome for inline SVG slashed LCP by 23%.

5  |  Putting It All Together – A Checklist

  1. Analyze your bundles after every dependency addition.
  2. Split routes & heavy components with next/dynamic.
  3. Inline only the CSS needed for FCP.
  4. Ship SVGs/icons smartly—avoid icon fonts.
  5. Monitor Web‑Vitals in production and iterate.

6  |  Conclusion

Client‑Side Rendering isn’t dead—it just demands discipline. By treating every kilobyte of JavaScript as a cost and applying the patterns above, you keep CSR fast, SEO‑friendly enough, and enjoyable to build.


Inspired by pages on CSR, bundle‑splitting and performance tuning in **Learning Patterns* (Hallie & Osmani, 2021).*

Top comments (0)