The React Compiler, stabilised in React 19, automatically optimises React applications by analysing component code at build time and inserting memoisation where needed — eliminating the need for manual useMemo, useCallback, and React.memo calls. For most applications, this means a significant reduction in boilerplate and more consistent performance without developer effort.
What Is the React Compiler?
The React Compiler (previously known as React Forget) is a build-time compiler that transforms React component code to automatically add memoisation where React's rules of React guarantee it is safe to do so. The compiler analyses the data flow through your components — which values depend on which props and state — and inserts the equivalent of useMemo and useCallback calls to prevent unnecessary re-renders, without the developer needing to write or maintain that memoisation code manually.
useMemo, useCallback, and React.memo in most cases, while maintaining correct rendering behaviour.The Problem: Manual Memoisation Is Error-Prone
Before the React Compiler, preventing unnecessary re-renders required developers to manually wrap values in useMemo, functions in useCallback, and components in React.memo. This approach had three fundamental problems: it required developers to correctly identify which values needed memoisation (often non-obvious); it introduced bugs when dependency arrays were incorrect or stale; and it added significant boilerplate that obscured business logic.
// BEFORE React Compiler — manual memoisation required
function ProductList({ products, onSelect, filters }) {
// Developer must remember to memoize every derived value
const filteredProducts = useMemo(
() => products.filter(p => filters.category === p.category),
[products, filters.category] // easy to get dependency array wrong
);
const handleSelect = useCallback(
(id) => onSelect(id),
[onSelect] // boilerplate with no business value
);
return filteredProducts.map(p => (
<ProductCard key={p.id} product={p} onSelect={handleSelect} />
));
}
// AFTER React Compiler — compiler handles this automatically
function ProductList({ products, onSelect, filters }) {
const filteredProducts = products.filter(
p => filters.category === p.category
);
return filteredProducts.map(p => (
<ProductCard key={p.id} product={p} onSelect={onSelect} />
));
// Compiler inserts memoisation automatically — same performance, no boilerplate
}
How the React Compiler Works
useMemo/useCallback with correctly computed dependency arrays. The transformed code is semantically equivalent to what an expert React developer would write manually.Setting Up the React Compiler
# Install the compiler babel plugin
npm install --save-dev babel-plugin-react-compiler
# For Vite projects — vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [
react({
babel: {
plugins: ['babel-plugin-react-compiler'],
},
}),
],
});
# For Next.js — next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
reactCompiler: true,
},
};
module.exports = nextConfig;
You can adopt the React Compiler incrementally using the compilationMode: "annotation" option, which only compiles components explicitly annotated with "use memo" or "use forget" directives. This allows you to test the compiler on specific components before enabling it application-wide — useful for large codebases where you want to validate behaviour before a full rollout.
When the Compiler Skips Optimisation
The React Compiler only optimises code that follows React's rules. It will skip (leave unoptimised) components and hooks that: mutate props or state directly; call hooks conditionally; have side effects in render without useEffect; use patterns that violate referential transparency. The compiler emits warnings for skipped components, making it straightforward to identify and fix violations. The eslint-plugin-react-compiler package provides ESLint rules that catch violations at development time.
When to Still Use useMemo and useCallback
| Scenario | Compiler Handles? | Recommendation |
|---|---|---|
| Computed values from props/state | ✅ Yes | Remove manual useMemo — compiler is more accurate |
| Event handlers passed as props | ✅ Yes | Remove useCallback boilerplate |
| Expensive pure computations (sorting large arrays) | ✅ Yes | Compiler handles — but verify with React DevTools Profiler |
| Values passed to non-React dependencies (e.g., charting libs) | ⚠️ Partial | May still need manual memo for external library stability |
| Context values to prevent consumer re-renders | ✅ Yes | Compiler optimises context consumers automatically |
| Referential equality required by useEffect deps | ✅ Yes | Compiler ensures stable references — simpler useEffect code |
React 19 Companion Features
The React Compiler ships as part of the broader React 19 release, which also includes: the Actions API for async state transitions without useReducer boilerplate; use() hook for reading context and promises in render; useOptimistic for optimistic UI updates with automatic rollback; Document Metadata support (<title>, <meta> directly in components); and improved Server Actions for full-stack React applications in Next.js and Remix.