React’s development team has been quietly working on a compiler to improve the default performance of applications that rely on React. The goal is a compiler that comprehends both JavaScript and React and outputs optimized versions of both; a major undertaking. Word is the compiler is no longer a research project and has been deployed to Instagram in production. That means it’s time for React developers to check out the new compiler and understand how it works.
What the React compiler does
The new React compiler is dedicated to performance optimization. In essence, it compiles an existing codebase into something new by eliminating as much re-rendering as possible.
The compiler automatically decorates your code with memoization, a kind of caching. Specifically, it adds the hooks useMemo and useCallback. Normally, these hooks are manually added, so the developer decides when to use them. But it’s easy to forget to add the hooks, or goof up the process, and it’s not always obvious when to use them.
Manual hooks also add noise to your codebase, since you are sprinkling code intended to improve efficiency around your business logic.
The React compiler solves these issues. You just write your code how you normally would and then run it through the compiler as part of your build chain. The resulting output is your code with the memoization wrappers added.
Why we need a React compiler
Re-rendering the codebase is computationally expensive and can degrade the overall performance of React and reactive applications. Unfortunately, React’s naive approach to reactivity means that such re-rendering can occur in many areas of a real-world application. As an example, consider a list of complex objects where the property on one object changes. This change flags the entire list display as “dirty’ and requiring re-rendering, when in fact, only the single property at the leaf of the tree requires updating. This issue can be especially problematic because touching the browser DOM is always one of the most expensive things the front end can do.
Such re-rendering isn’t limited to React; it can be an issue for any reactive engine. React also isn’t the first engine to introduce a compiler to address this issue. One example is Svelte, which had a built-in compiler from its inception. That was a radical departure from the conventional approach at the time, but it’s gradually gained traction. Another example is Solid. Like React and unlike Svelte, the Solid compiler is not built into the engine but is an additional piece you can use to improve application performance. The React and Solid compiler implementations are different, but the overall spirit is similar.
Developing the React compiler
Developing a compiler for React is a massive undertaking. The React engine allows for any JavaScript constructs in its logic and data. It also offers a fairly high degree of flexibility and complexity, along with the JSX syntax. React’s development team wanted a compiler capable of consuming and understanding an arbitrary application codebase well enough to automatically apply sophisticated hooks like useMemo
and useCallback
. They addressed the challenge by moving incrementally to cover smaller language features like for-loops and if-else constructs, before moving on to more ambitious structures.
The result is a generalized compile-time engine for consuming and outputting modified React components. If you’re wondering whether the new compiler is worth looking into, consider these words from the React team:
If your codebase is already very well-memoized, you might not expect to see major performance improvements with the compiler. However, in practice memoizing the correct dependencies that cause performance issues is tricky to get right by hand.
How to use the React compiler
The React.dev docs now have a dedicated section for the React compiler. The compiler is still considered experimental, but it is being used in production by Meta, and it’s likely to become a standard part of the React toolchain. The compiler requires React 19.
Besides being valid JavaScript, components intended for compilation must follow the Rules of React. You can use the React eslint
plugin to ensure your components meet the requirements:
npm install eslint-plugin-react-compiler@experimental
If you want to check the health of your codebase before using it with the compiler, the following tool outputs an overview, including how many components are ready for compilation:
npx react-compiler-healthcheck@experimental
A Babel plugin for the compiler can be integrated with all the mainstream JavaScript build tools like Webpack and Vite. Next.js also has an experimental configuration for it.
If a particular component is giving you trouble, you can issue a “use no memo” directive to temporarily opt out of using the compiler.
The general outlines for using the compiler are relatively simple:
- Ensure your components are well-behaved.
- Add the compiler to the build pipeline.
- Serve the compiled versions of the components to clients.
Et voilà! You have magically memoized versions of your components ready to be served. Of course, theory and practice are never perfectly aligned and there are also steps for troubleshooting and issue reporting if you need them.
The more complex and extensive your codebase, the more wrangling you will likely need to do to incorporate the compiler. Another area to be aware of is third-party libraries, which may not be compatible with the compiler (the compatibility tool will flag known incompatibilities).
Tradeoffs of the React compiler
The introduction of React’s compiler is an interesting development for both the framework and the front-end space. For React, server-side compilation introduces additional preparation, but it also opens up many possibilities. Generally speaking, automated optimization for memoization could broadly improve React apps, which is welcome news for developers and users both.
If successful, the React compiler could spur similar types of efforts in other frameworks, both those that use a compiler already and those that don’t. React’s incorporation of a compiler tacitly acknowledges that pairing a compiler with a reactive engine is a good idea.
The trade-off is that you have to involve server-side build tooling, but in practice that is usually the case for many applications. There is additional tooling overhead and maintenance if you integrate the compiler, but it’s not a huge amount of work. Certainly, it’s more work to add caching to an entire application. Also, you also have the option to omit the compiler and use simple front-end React from a script include.
Conclusion
It’s tempting to speculate on how far we might go in moving work into the compiler and out of the in-browser engine. The more work that stays out of the browser—that is, the more efficient the code that is shipped to the front end—the better-performing the final engine will be. At what point does this process start to change the basic nature of React?
Regardless of where you land on that question, the compiler is an interesting move from React. It’s also right in line with the overall trend of compounding innovation and cross-pollination in a space that seems to perpetually seek new and creative approaches.