Every React 19 kickoff call we've run since late last year eventually gets to the same question: should we turn on React Compiler? For a while the honest answer was "not yet" — it was experimental, its coverage was inconsistent, and turning it on meant babysitting edge cases nobody had documented yet. That changed on October 7, 2025, when React Compiler hit its 1.0 release, and it's now had roughly a year running in production at real scale. The tool isn't the risk anymore. The risk is treating React Compiler as a substitute for understanding your own render tree, instead of what it actually is: something that removes the tedious 80% of manual memoization and leaves the interesting 20% to you.
What React Compiler actually does
React Compiler analyzes your component and hook code at build time — as a Babel plugin, a Vite plugin, or wired directly into Next.js's build pipeline — and automatically inserts the equivalent of useMemo, useCallback, and React.memo wherever it can prove doing so is safe and worthwhile, without you writing any of it by hand. That's the actual headline change: for most components, manual memoization stops being something you reach for reflexively while writing a component and becomes an implementation detail the compiler handles for you.
It works on React 17 and 18 as well as 19 (older versions need a small runtime package alongside it), and Meta didn't call it production-ready until it had been validated against Instagram, the Quest Store, and other large internal apps first. This isn't a hypothetical optimization pitched at toy examples — it's already running on some of the highest-traffic React surfaces that exist.
The numbers are real, and they vary a lot
Meta's own release notes reported initial loads and cross-page navigations improving by up to 12% on Quest Store after enabling React Compiler, with some interactions running more than 2.5x faster and memory usage staying neutral. Instagram, by contrast, saw about a 3% improvement across pages overall — smaller, because Instagram's codebase already had years of hand-tuned manual memoization squeezing out redundant work before the compiler ever got involved. Outside Meta, Sanity Studio — a large open-source React codebase — compiled 1,231 of its 1,411 components and measured a 20-30% reduction in render time and latency. Wakelet reported roughly 10% LCP and 15% INP improvements after adopting it, with plain, non-virtualized components seeing INP gains closer to 30%.
The pattern across all four is consistent: the less disciplined a codebase already was about memoization, the more React Compiler has to work with. A codebase full of prop-drilled callbacks and components re-rendering on every parent update is exactly where automatic memoization pays off hardest. A codebase that already wrapped every expensive computation in useMemo sees a smaller, still real, gain — because there was less redundant work left on the table to begin with.
What React Compiler still won't touch
Effects, refs, and mutation are the three places manual thinking doesn't go away. React Compiler can't safely optimize an effect — cleanup, dependency arrays, and execution timing are still entirely your responsibility, because effects are inherently about side effects the compiler has no static way to reason about. Ref mutations are invisible to it in the same way: reading or writing a ref during render, or mutating a value the compiler can't trace through props, falls outside what it can prove safe, so it leaves that code exactly as written rather than guessing at your intent.
Context is the subtler case. The compiler can memoize some context-consumption patterns, but the reliable approach hasn't changed: read what a component actually needs from context in an outer, less-frequently-updating component, then pass those specific values down as props to the memoized child, rather than letting every consumer subscribe to the entire context value directly.
You'll also still reach for useMemo or useCallback by hand in a narrower set of cases — when an external library or an imperative API (an animation handle, a ref-based integration) needs a guaranteed stable identity the compiler's own tracking can't promise, or when a value specifically has to stay referentially stable because it feeds a useEffect dependency array. Those are escape hatches for precise control now, not the default tool you'd use to fix every rerender.
The linter is the real gate, not the compiler
The part that catches teams off guard isn't the compiler itself — it's that React Compiler silently skips any component or hook that violates the Rules of React instead of throwing an error, which means a codebase that's sloppy about those rules ends up with partial, uneven optimization and no obvious signal about which components got left out. The fix is running eslint-plugin-react-hooks with its recommended-latest preset, which now bundles the compiler-specific lint rules — purity, immutability, refs, set-state-in-render, and several others — alongside the existing exhaustive-deps and rules-of-hooks checks. Run that before you flip the compiler on, not after something already shipped looks slower than expected. How lint-clean a codebase is against that preset is what actually determines how much of the app React Compiler can touch.
A safe rollout plan for an existing app
Turning the compiler on everywhere in one pull request makes problems hard to attribute. A staged rollout is slower for a day and faster over a month.
- Upgrade lint first. Enable the React Hooks recommended rules and fix what they report.
- Measure before you change anything. Record a few interactions with the React Profiler and a performance trace so you can compare.
- Enable the compiler for one directory that shows up in profiling, not one that merely feels slow.
- Run the test suite and click through the screen. Look for stale values and missing updates.
- Compare the profile. Keep the change only where it measurably helps.
- Expand gradually, excluding any component that misbehaves with the
"use no memo"directive and filing a note about why.
function ProductRow({ product }: { product: Product }) {
"use no memo"; // opt this component out while we investigate an edge case
return <Row data={product} />;
}What to keep doing by hand
- Effects: dependencies, cleanup and timing remain your responsibility.
- Stable identity contracts: a value feeding an effect's dependency array, or a prop an external library requires to stay referentially stable.
- Data shape: compilers cannot fix a state design that causes needless renders. Structure state so each piece changes independently.
- List performance: very long lists still need virtualization.
What we'd actually recommend
On a new React 19 build, we turn React Compiler on from day one through the Babel or Vite plugin and treat manual useMemo, useCallback, and memo as something we add back deliberately, not something we write reflexively while building the first pass of a component. That alone removes a category of premature-optimization decisions a team would otherwise make blind, before there's any real performance data to justify them.
On an existing codebase, we don't flip it on for the whole app in one pull request. We run eslint-plugin-react-hooks's recommended-latest preset first, fix what it flags, then enable the compiler directory by directory — starting with the screens that actually show up in performance profiling, not the ones that just feel slow. If a specific component misbehaves after compilation, the "use no memo" directive lets you exclude it and file the edge case rather than blocking the rollout for the rest of the app. And whatever the compiler takes off your plate, we still keep the useMemo calls tied to actual referential-stability requirements — an external library's expected prop identity, an effect's dependency array — because those aren't performance hints the compiler can second-guess. They're contracts.
Frequently asked questions
Sources

Written by
Hamza Fazal
Founder, DEESU
Muhammad Hamza Fazal is the Founder of DEESU. An Android and full-stack web developer and digital marketer based in Islamabad, he founded DEESU in May 2022 and leads its engineering operations, product strategy, and client software delivery.
More from HamzaFree tools for this topic
Need help with this?