For a Next.js 16 App Router app in late 2026, turn the React Compiler on when your client components re-render more than they should and your Rules of React lint is clean. Wait when cold builds already hurt CI, when a large share of the UI breaks the rules the compiler needs, or when you still ship webpack in production and cannot spare a Babel pass. That is the short answer. The rest is how Next.js wires the compiler today, what the Babel path costs versus the experimental Rust path, and a rollout that does not surprise users.
React Compiler 1.0 shipped in October 2025. Next.js 16 moved reactCompiler out of experimental and left it off by default while the team keeps collecting build-time numbers across app shapes. You still opt in on purpose.
What the compiler actually changes
The compiler is a build-time transform. It rewrites components and hooks so values, callbacks, and JSX get cached between renders and recompute when their inputs change. Meta’s public notes on the Quest Store reported up to about 12% faster initial loads and cross-page navigations, with some interactions more than 2.5× faster. You keep writing plain components. Most of the useMemo, useCallback, and React.memo bookkeeping moves into the build.
It does not replace every memo. List rows whose parent still re-renders can need an explicit boundary. Code that breaks the Rules of React gets skipped, not “fixed.” Components the compiler skips keep working; they stay unoptimized. React DevTools marks optimized components with a Memo badge, and the compiled output imports from react/compiler-runtime, which is a useful sanity check after you flip the flag.
How Next.js 16 enables it
Install the Babel plugin and set the top-level option:
1pnpm add -D babel-plugin-react-compiler
1import type { NextConfig } from 'next'23const nextConfig: NextConfig = {4 reactCompiler: true,5}67export default nextConfig
Next.js does not Babel every file. A custom SWC pass finds files that look like JSX or Hooks and sends those through the compiler. Builds still get slower than the default Rust pipeline, but the cost stays local compared with a naive Babel-everywhere setup. Official upgrade notes are blunt about this: expect higher compile times in development and production builds because the stable path still relies on Babel.
If you are still on webpack for production, that Babel path is what you get. For context on Turbopack as the Next.js 16 default versus staying on webpack, see Turbopack vs Webpack on Next.js 16.
Babel vs the experimental Rust compiler
From Next.js 16.3 you can try the native Rust React Compiler inside Turbopack:
1import type { NextConfig } from 'next'23const nextConfig: NextConfig = {4 reactCompiler: true,5 experimental: {6 turbopackRustReactCompiler: true,7 },8}910export default nextConfig
This flag selects the implementation. It does not turn the compiler on by itself. The Rust option works with Turbopack alone; pairing it with webpack throws. With the Rust path you do not need babel-plugin-react-compiler installed.
Independent benchmarks on a small Next.js 16.4 app (compiler off vs Babel vs Rust) are useful as a shape check, not as your number. In one published run, twenty counter clicks caused twenty thousand list-row re-renders with the compiler off and zero with either compiler on; scripting time in that interaction dropped from about 60 ms to about 7 ms. The Babel compile step more than doubled on that app; the Rust path added about a quarter of a second and produced byte-identical client output to Babel. Your monorepo will not match those wall times. Measure next build and a hot refresh on a representative route before you argue about CI minutes.
When to enable it now
Enable the full compiler when most of these are true:
- Client-heavy routes show wasted re-renders in React DevTools or the Profiler, and you keep sprinkling memo by hand.
eslint-plugin-react-hookson therecommended-latestpreset is clean, or the remaining violations sit in corners you can mark with"use no memo".- You already ship Turbopack in CI, so you can try
turbopackRustReactCompilerif Babel compile cost shows up in the build graph. - Product metrics you care about (interaction latency, list scrolling, dashboard filters) are client-bound, not blocked on data fetching. Server Components and a query layer still do the heavy lifting for server work; see Server Components did not replace TanStack Query.
Also run the React Compiler ESLint rules before you flip production. A reported error means the compiler skips that component or hook. That is safe. Fixing every violation on day one is optional; the lint queue is the adoption backlog.
When to wait (or adopt in annotation mode)
Wait on a full enable when:
- Cold
next buildis already the slowest step in CI and you cannot absorb another Babel pass this quarter. Prefer annotation mode or a single directory first. - Large islands mutate refs during render, read from unstable module state, or otherwise trip Rules of React. The compiler will skip them; you still pay some analysis cost and get little benefit until you clean those islands up.
- You are mid-migration on the test runner or the lint stack and cannot tell a compiler regression from a tooling change. Stabilize Vitest or Jest and Biome vs ESLint first if those projects are open.
- Production still requires webpack and leadership will not accept a measurable build regression without a user-facing win you can show in a week.
For a controlled rollout, Next.js supports annotation mode:
1import type { NextConfig } from 'next'23const nextConfig: NextConfig = {4 reactCompiler: {5 compilationMode: 'annotation',6 },7}89export default nextConfig
Then opt in per component or hook:
1export default function ExpensiveList({ items }: { items: Item[] }) {2 'use memo'3 // ...4}
Use "use no memo" to exclude a problematic unit while you fix it. The React docs also describe Babel overrides for directory-based adoption and a gating option for runtime feature flags when you want an A/B split. On a Next.js app the practical path looks like this: lint clean on one feature folder, enable annotation there, confirm DevTools badges and no behavior change, then flip reactCompiler: true for the app.
A rollout that survives contact with production
- Install
eslint-plugin-react-hooks@latestand turn on the compiler-aware rules. Triage skips; do not block the merge on cleaning the whole repo. - Enable annotation mode on staging. Tag two or three hot client components with
"use memo". - Compare Profiler traces and a real user path (filter a table, type in a search box, open a drawer) before and after.
- If you build with Turbopack, try
experimental.turbopackRustReactCompileron a branch and record wall time fornext buildand a coldnext devboot. - After that, set
reactCompiler: truewithout annotation. Keep"use no memo"as an escape hatch, not as a permanent architecture.
Do not rip out every useMemo the week you enable the compiler. Existing memoization still documents intent for humans, and Next.js lets you configure whether the compiler preserves those guarantees. Set that explicitly if you care about consistent behavior across compiler implementations.
The decision in one line
If client re-renders are burning users and your lint is clean enough to ship, enable React Compiler on Next.js 16 and prefer the Rust Turbopack path when you can measure it. If builds are the constraint or the UI is full of rule breaks, stay on annotation mode or wait. The flag is stable; your app’s readiness is not automatic.