React

Turning the React Compiler on by default across new projects

RCT

Last year we tested the React Compiler cautiously, project by project, watching closely for the subtle correctness issues that any automatic memoization tool risks introducing. A year of real production usage across several of those pilots gave us enough confidence to make it the default for every new React project going forward, rather than continuing to evaluate it case by case.

Manual memoization has become something we write only for the rare case the compiler's bailout diagnostics flag, rather than a habit applied everywhere by default the way it used to be. That shift changes the shape of a typical pull request review: instead of checking whether a component correctly wraps its callbacks and computed values in the right memoization hooks, reviewers now mostly just check whether the compiler is actually able to optimize the component at all, and if it isn't, why not. The compiler's bailout diagnostics turned out to be more useful than we expected going in, since a component the compiler can't safely optimize is often a component with a pattern worth reconsidering anyway, an unstable prop reference, a side effect hiding somewhere it shouldn't be.

The mental overhead of thinking about re-renders has dropped noticeably across the team. Junior engineers in particular used to spend real energy learning when and how to reach for `useMemo` and `useCallback` correctly, a skill that took months to build real intuition for and that experienced engineers sometimes disagreed about in code review. That entire category of discussion has mostly gone quiet. It hasn't disappeared completely, there are still edge cases the compiler can't safely handle and a developer needs to recognize those cases, but the frequency of that kind of conversation dropped enough that it freed up real review time for discussing actual application logic instead.

Migrating existing projects onto the compiler took more care than starting fresh with it. A codebase with years of manual memoization already in place needed a careful pass to identify memoization that had become redundant under the compiler versus memoization that was still doing something the compiler couldn't infer on its own, usually around expensive computations gated behind conditions the compiler couldn't statically verify were safe to skip. We didn't strip out every existing `useMemo` call reflexively; a few were left in place specifically because removing them and trusting the compiler to infer the same optimization introduced a small but measurable performance regression in profiling.

The honest caveat is that the compiler doesn't remove the need to understand what re-rendering actually costs and why. It removes the need to manually annotate that understanding into every component by hand, but a developer who doesn't understand why a re-render might be expensive in the first place will still write code that performs poorly, they'll just do it without the compiler's bailout diagnostics giving them a clear signal to investigate. We still spend real time in onboarding explaining the underlying rendering model, the compiler changed what engineers write day to day, not what they need to understand to write it well.

← Back to the journal

Have a project in mind?
Let’s talk.

Tell us where you are and where you want to go. We'll map the fastest route between the two.

Currently accepting new clients