XplormityXplormity
HomeHandbooks
Browse
Xplormity

TLDR developer handbooks for
seasoned developers.

Handbooks

RustNestJSNext.jsGitDockerTypeScriptReactNode.jsDSASQLSystem DesignTailwind CSS

Site

HomeHandbooksAboutPrivacyTerms

Connect

GitHubTwitterLinkedIn

© 2026 Xplormity. All rights reserved.

HandbooksNext.jsTurbopack & Performance

Turbopack & Performance

turbopackperformancebundlerhandbook

TL;DR

  • Turbopack is Next.js 16's default bundler — Rust-based, 2-5x faster builds than Webpack.
  • Filesystem caching persists compilation across dev server restarts.
  • React Compiler auto-memoizes components (opt-in).
  • Prefetching is smarter: layout deduplication + incremental prefetch.

Step 1: Turbopack — The New Default

Turbopack was built because Webpack became the bottleneck for large Next.js apps — developers at companies like Vercel and Meta reported 30-60 second cold starts and multi-second HMR updates on large codebases. Written in Rust (like SWC), Turbopack uses incremental computation (only recompiles what changed) and persistent caching to achieve near-instant updates regardless of project size. It's not just faster Webpack; it's a fundamentally different architecture designed for the scale of modern monorepos.

Turbopack replaces Webpack as the default bundler in Next.js 16. No configuration needed.

Performance Numbers

Metric Webpack (Next.js 15) Turbopack (Next.js 16) Improvement
Dev startup ~1100ms ~600ms 2x faster
Production build ~28s ~6s 4.7x faster
Fast Refresh ~300ms <100ms 3x faster
Hot Module Replacement Per-page Per-component More granular

How It Works

  • Written in Rust for native speed
  • Incremental computation: only re-processes what changed
  • Parallel processing across CPU cores
  • Tree-shaking at the module level (not bundle level)

Step 2: Filesystem Caching

Filesystem caching in Turbopack solves the "cold start" problem that plagued Webpack: every time you restarted your dev server, it had to recompile everything from scratch. Turbopack now persists compiled modules to disk, so the second startup only processes files that changed since last time. For large projects (500+ modules), this reduces dev server startup from 10+ seconds to under 1 second. It's the same concept as incremental compilation in languages like Rust and Go, applied to JavaScript bundling.

Stable since Next.js 16.1 — persists compilation results to disk:

// next.config.ts
const nextConfig = {
  experimental: {
    turbopackFileSystemCacheForDev: true,    // Cache during dev
    turbopackFileSystemCacheForBuild: true,  // Cache between builds
  },
};

export default nextConfig;

What This Means

  • First startup: Normal speed (cold cache)
  • Subsequent startups: Near-instant (reads from .next cache)
  • Dependency updates: Clear .next folder to invalidate
# If you see stale behavior after upgrading packages:
rm -rf .next && npm run dev

Step 3: React Compiler (Stable, Opt-In)

The React Compiler was the most anticipated feature in the React ecosystem for years. It automatically inserts useMemo, useCallback, and React.memo at build time by analyzing your component's data flow. This eliminates the performance optimization tax that React developers have paid since 2018 — no more wrapping every callback in useCallback or debating whether to memo a component. In Next.js 16, enabling it is a one-line config change that instantly optimizes your entire app without changing a single component.

The React Compiler automatically memoizes components and hooks — no more manual useMemo, useCallback, React.memo:

// next.config.ts
const nextConfig = {
  reactCompiler: true,
};

Before (Manual Memoization)

"use client";
import { useMemo, useCallback } from "react";

function ExpensiveList({ items, filter }: Props) {
  const filteredItems = useMemo(
    () => items.filter(item => item.category === filter),
    [items, filter]
  );

  const handleClick = useCallback((id: string) => {
    console.log("clicked", id);
  }, []);

  return filteredItems.map(item => (
    <Item key={item.id} item={item} onClick={handleClick} />
  ));
}

After (React Compiler Does It)

"use client";

function ExpensiveList({ items, filter }: Props) {
  // Compiler auto-memoizes this computation
  const filteredItems = items.filter(item => item.category === filter);

  // Compiler auto-memoizes this callback
  const handleClick = (id: string) => {
    console.log("clicked", id);
  };

  return filteredItems.map(item => (
    <Item key={item.id} item={item} onClick={handleClick} />
  ));
}

When to Enable

✅ Enable if: Heavy client-side interactivity, many re-renders, complex UIs ❌ Skip if: Mostly server-rendered pages, third-party libraries not compatible


Step 4: Improved Prefetching

Prefetching was rewritten in Next.js 16 because the old implementation had two problems: it fetched too eagerly (wasting bandwidth on links users never click) and its cache invalidation was unpredictable (showing stale data). The new implementation uses smarter heuristics — only prefetching visible links with idle-time priority, and using stale-while-revalidate patterns so navigation feels instant while data stays fresh. This directly improves Largest Contentful Paint (LCP) and perceived navigation speed.

Next.js 16 rewrote the prefetch cache with two optimizations:

Layout Deduplication

If 10 navigation links share the same layout, Next.js downloads the layout once instead of 10 times.

Before: Link 1 prefetch = layout + page1
        Link 2 prefetch = layout + page2  ← redundant layout download
        Link 3 prefetch = layout + page3  ← redundant layout download

After:  Layout prefetch = layout (once)
        Link 1 prefetch = page1 only
        Link 2 prefetch = page2 only
        Link 3 prefetch = page3 only

Result: 60-80% less data transfer on pages with many navigation links.

Incremental Prefetching

Only fetches parts of the route not already cached:

Visit /dashboard → layout + page cached
Click /dashboard/settings → only fetches settings page (layout already cached)

Automatic Cancellation

Links that scroll out of viewport have their prefetch cancelled — prevents wasted bandwidth on long pages with many links.


Step 5: Server Fast Refresh (16.2)

Server Fast Refresh was one of the most requested developer experience features since the App Router launched. Previously, editing a Server Component required a full page reload because there was no HMR mechanism for server-rendered content. In Next.js 16.2, changes to Server Components hot-swap without losing client state — the same instant feedback loop developers loved for Client Components now works everywhere. This dramatically speeds up the develop-preview-iterate cycle for server-heavy applications.

New in 16.2: Hot module replacement now works for server components too.

Before: Edit server component → full page reload
After:  Edit server component → only that component re-renders on server

This makes the development loop significantly tighter for server-heavy applications.


Step 6: Optimization Checklist

This checklist represents the collective knowledge of the Next.js performance community — the settings and patterns that consistently deliver the best Core Web Vitals scores. Each item addresses a specific performance bottleneck: image optimization prevents layout shift (CLS), dynamic imports reduce initial bundle size (LCP), proper cache headers eliminate redundant requests, and bundle analysis reveals unexpected dependency bloat. Run through this checklist before any production deployment.

Production Build Optimization

// next.config.ts
const nextConfig = {
  cacheComponents: true,
  reactCompiler: true,  // Only if your app is client-heavy
  experimental: {
    turbopackFileSystemCacheForBuild: true,
  },
  images: {
    // Increase cache TTL (default is now 4 hours in Next.js 16)
    minimumCacheTTL: 86400, // 24 hours
  },
};

Bundle Analysis

# Next.js 16.1+ built-in analyzer
ANALYZE=true next build

Key Performance Patterns

  1. Use Server Components by default — zero client JS for static content
  2. "use cache" on expensive data fetches — avoid re-fetching on every request
  3. <Suspense> boundaries around cached components — show skeleton while loading
  4. Dynamic imports for heavy client components — code-split at component level
import dynamic from "next/dynamic";

// Only loaded when needed — not in initial bundle
const HeavyChart = dynamic(() => import("./Chart"), {
  loading: () => <ChartSkeleton />,
  ssr: false, // Skip server render for client-only components
});

Interview Questions

  1. What's Turbopack and why is it faster?

    • Rust-based bundler with incremental computation. Only reprocesses changed modules. Parallel processing across cores.
  2. What does the React Compiler do?

    • Automatically memoizes components, values, and callbacks. Eliminates the need for manual useMemo/useCallback/React.memo.
  3. How does filesystem caching work in Turbopack?

    • Compilation artifacts are persisted to disk in .next. Subsequent dev server starts skip recompilation for unchanged code.
  4. How is prefetching optimized in Next.js 16?

    • Layout deduplication (shared layouts fetched once) + incremental prefetching (only missing data fetched) + viewport cancellation.
Cache Components & Caching (Next.js 16)proxy.ts & Routing (Next.js 16)

On this page

  • TL;DR
  • Step 1: Turbopack — The New Default
  • Performance Numbers
  • How It Works
  • Step 2: Filesystem Caching
  • What This Means
  • Step 3: React Compiler (Stable, Opt-In)
  • Before (Manual Memoization)
  • After (React Compiler Does It)
  • When to Enable
  • Step 4: Improved Prefetching
  • Layout Deduplication
  • Incremental Prefetching
  • Automatic Cancellation
  • Step 5: Server Fast Refresh (16.2)
  • Step 6: Optimization Checklist
  • Production Build Optimization
  • Bundle Analysis
  • Key Performance Patterns
  • Interview Questions