Turn on the React Compiler (Where Supported) to Reduce Re-render Costs
24 Feb 2026React performance problems in large React Native and Expo projects almost always trace back to the same root cause: wasted re-renders. As component trees grow, the cost of unnecessary reconciliation quietly compounds. Developers respond with useMemo, useCallback, React.memo, and hand-rolled optimizations, often inconsistently, sometimes incorrectly, and always at a cognitive cost.
The React Compiler changes this equation. When enabled, it can automatically infer memoization boundaries, drastically reducing re-renders without manual intervention. Despite this, it remains significantly underused in React Native and Expo projects.
In this article I explain why enabling the React Compiler is one of the highest-leverage performance improvements you can make today, how it works, where it is supported, and what you should do as a developer to take advantage of it.
The Real Cost of Re-renders in RN and Expo
In React Native, re-renders are more expensive than in web React:
- The bridge (or JSI) amplifies render costs
- Layout and measurement are non-trivial
- Large lists and deeply nested trees are common
- Animations often depend on render stability
A single state change near the root can easily trigger hundreds of component re-executions, even when most outputs don’t change.
The traditional mitigation strategy looks like this:
const Item = React.memo(function Item({value}) {
return <Text>{value} < /Text>
});
const List = ({items}) => {
const renderItem = useCallback(
({item}) => <Item value={item.value}/>,
[]
);
return <FlatList data={items} renderItem={renderItem}/>;
};
This works, but it comes with problems:
- Developers must predict what should be memoized
- Dependency arrays are easy to get wrong
- Refactors frequently break memoization
- Code becomes harder to read and maintain
Most teams either over-memoize (wasting memory) or under-memoize (wasting CPU). The React Compiler exists to remove this tradeoff.
What the React Compiler Actually Does
The React Compiler is a build-time optimization that analyzes your components and automatically memoizes values, callbacks, and subtrees when it is safe to do so.
Key properties:
- Runs at compile time (not runtime)
- Preserves React semantics
- Understands component purity
- Eliminates unnecessary re-renders
- Replaces most manual
useMemo/useCallback
In other words: React becomes closer to how developers assume it already works.
Why This Is Still Underused in React Native and Expo
Despite its benefits, many RN and Expo projects have not enabled the React Compiler. The reasons are mostly practical, not technical:
- Tooling lag: RN projects often trail web React in adopting new compiler features.
- Fear of instability: Mobile teams are more conservative about build pipelines.
- Legacy Babel configurations: Many projects still use complex, brittle Babel setups.
- Habitual over-memoization: Teams have internalized manual memoization as “best practice.”
The result: teams continue paying re-render costs they no longer need to pay.
This is a mistake. On large trees, the compiler routinely removes 30–70% of wasted renders with zero runtime cost.
Where the React Compiler Is Supported
As of now, the React Compiler is supported in:
- React 19+ (experimental but stabilizing)
- Metro + Babel pipelines (including React Native)
- Expo projects using the new Expo CLI and Metro config
- Webpack/Vite setups for web
Expo projects are actually well-positioned to adopt it because Expo already standardizes much of the build chain.
Enabling the React Compiler
1. Update React
You must be on a compatible React version:
{
"dependencies": {
"react": "^19.0.0",
"react-native": ">=0.75"
}
}
2. Enable the Babel Plugin
Add the compiler plugin to your Babel config:
module.exports = {
presets: ['babel-preset-expo'],
plugins: [
['react-compiler', {target: 'react-native'}]
],
};
For non-Expo RN projects, ensure Metro uses this Babel config consistently.
Removing Manual Memoization (Yes, Really)
Once the compiler is enabled, you should actively remove unnecessary memoization.
Before:
const total = useMemo(() => {
return items.reduce((sum, i) => sum + i.price, 0);
}, [items]);
const onPress = useCallback(() => {
submit(total);
}, [total]);
After:
const total = items.reduce((sum, i) => sum + i.price, 0);
const onPress = () => {
submit(total);
};
The compiler will memoize both total and onPress if (and only if) doing so prevents wasted work.
This leads to:
- Cleaner components
- Fewer hooks
- Fewer bugs from stale dependencies
- Better long-term maintainability
Manual memoization should now be the exception, not the rule.
Large Component Trees Benefit the Most
Consider a common pattern in RN apps:
<App>
<Navigation>
<Screen>
<Header/>
<Content>
<Feed>
<Post/>
<Post/>
<Post/>
</Feed>
</Content>
</Screen>
</Navigation>
</App>
A state change in Screen often re-renders the entire subtree—even if only Header actually changed.
With the compiler enabled:
- Stable subtrees are automatically skipped
- Post components do not re-render unless props change
- Developers do not need to wrap everything in
React.memo
This is particularly impactful in:
- Feeds
- Dashboards
- Forms with many controlled inputs
- Navigation-heavy layouts
When You Still Need Manual Control
The React Compiler is powerful, but not magic. You still need to think about:
- Side effects (
useEffectsemantics remain unchanged) - Referential identity for external libraries
- Performance-critical animation code
- Mutable refs and imperative APIs
If a callback is passed into a non-React system that depends on identity stability, explicit memoization can still be appropriate.
The difference is intent: you now optimize only when necessary.
What Developers Should Do Today
- Enable the React Compiler in new projects by default
- Audit existing projects for unnecessary memoization
- Delete
useMemo/useCallbackthat exist “just in case” - Measure re-renders before and after
- Treat manual memoization as a performance escape hatch
If you are maintaining a large RN or Expo codebase and have not tried the compiler, you are almost certainly leaving performance on the table.
Final Words
Manual memoization was always a tax on developer productivity. The React Compiler finally removes that tax.
In React Native and Expo projects, where render costs are higher and trees are deeper, not enabling it is a self-inflicted performance penalty. Turn it on where supported, simplify your components, and let the compiler do the work it was designed to do.
This is one of the rare cases where the best performance move is also the cleanest architectural choice.