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
.nextcache) - Dependency updates: Clear
.nextfolder 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
- Use Server Components by default — zero client JS for static content
"use cache"on expensive data fetches — avoid re-fetching on every request<Suspense>boundaries around cached components — show skeleton while loading- 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
-
What's Turbopack and why is it faster?
- Rust-based bundler with incremental computation. Only reprocesses changed modules. Parallel processing across cores.
-
What does the React Compiler do?
- Automatically memoizes components, values, and callbacks. Eliminates the need for manual
useMemo/useCallback/React.memo.
- Automatically memoizes components, values, and callbacks. Eliminates the need for manual
-
How does filesystem caching work in Turbopack?
- Compilation artifacts are persisted to disk in
.next. Subsequent dev server starts skip recompilation for unchanged code.
- Compilation artifacts are persisted to disk in
-
How is prefetching optimized in Next.js 16?
- Layout deduplication (shared layouts fetched once) + incremental prefetching (only missing data fetched) + viewport cancellation.