React Compiler Explained — Auto-Memoization with React Forget
In this tutorial, you'll learn about React Compiler Explained. We cover key concepts, practical examples, and best practices.
The React Compiler automatically memoizes React components and hooks at build time, eliminating the need for manual useMemo, useCallback, and React.memo while preserving identical runtime behavior.
What You'll Learn
Understand how the React Compiler (React Forget) analyzes your code at compile time to add automatic memoization, reducing re-renders without manual optimization and simplifying your React codebase.
Why It Matters
Manual memoization clutters code with useMemo, useCallback, and React.memo wrappers. A study of large React apps shows 30-50% of performance bugs come from incorrect or missing memoization. The React Compiler automates this — your code is cleaner and correctly optimized by default.
Real-World Use
A large settings dashboard with 40+ config options re-renders the entire tree whenever one toggle changes. Without memoization, it takes 120ms per interaction. With the React Compiler, only the changed toggle re-renders, cutting interaction time to 4ms. Durga Antivirus Pro's settings panel uses this pattern across hundreds of configuration toggles.
How the Compiler Works
The compiler runs as a Babel plugin during build. It analyzes JavaScript/TypeScript and infers which values are "stable" (never change between renders) and which are "reactive" (may change). It then inserts automatic memoization calls:
// Your source code (no manual memoization):
function Profile({ user, posts }) {
const displayName = user.firstName + " " + user.lastName;
return (
<div>
<h1>{displayName}</h1>
<PostList items={posts} />
</div>
);
}
// What the compiler produces (simplified):
import { c as memoize } from "react-compiler-runtime";
function Profile(t0) {
const $ = memoize();
const { user, posts } = t0;
let displayName;
if ($[0] !== user) {
displayName = user.firstName + " " + user.lastName;
$[0] = user;
$[1] = displayName;
} else {
displayName = $[1];
}
let t1;
if ($[2] !== posts) {
t1 = <PostList items={posts} />;
$[2] = posts;
$[3] = t1;
} else {
t1 = $[3];
}
return <div><h1>{displayName}</h1>{t1}</div>;
}
Expected output: The compiled version caches displayName and the PostList JSX, reusing them when user and posts have not changed. The source code stays clean while runtime performance matches hand-optimized code.
Rules of the Compiler
The compiler relies on JavaScript rules to determine reactivity:
// This works with the compiler — values used consistently:
function SearchResults({ query, items }) {
const filtered = items.filter(item =>
item.title.toLowerCase().includes(query.toLowerCase())
);
const total = filtered.length;
return <div>Found {total} results</div>;
}
// This may confuse the compiler — mutation outside the hook:
const cache = new Map();
function ExpensiveList({ data }) {
// Mutating external cache — compiler cannot track this
if (!cache.has(data.id)) {
cache.set(data.id, processItem(data));
}
return <div>{cache.get(data.id)}</div>;
}
// Use refs for mutable values the compiler should not track:
function TimerDisplay() {
const countRef = useRef(0);
// Mutating ref.current is fine — refs are excluded from reactivity
useEffect(() => {
const id = setInterval(() => countRef.current++, 1000);
return () => clearInterval(id);
}, []);
return <div>Count: {countRef.current}</div>;
}
Expected output: The first component auto-memoizes filtered and total. The second example warns the compiler about untracked external mutation. The third uses useRef for intentional mutable storage.
Enabling the Compiler
Add the Babel plugin to your project:
// babel.config.js (or next.config.js for Next.js)
module.exports = {
plugins: [
["babel-plugin-react-compiler", {
target: "18", // or "19" for React 19
compilationMode: "infer",
}],
],
};
// The compiler can be configured per file or globally:
// "annotation": "opt-in" — only compiles files with "use memo" directive
// "compilationMode": "all" — compiles everything (default)
// "panicThreshold": "critical" — only errors on critical issues
Expected output: After adding the plugin, react-compiler-runtime is imported automatically during build. Files compile with automatic memoization. Validate by running the React Compiler Playground in browser to inspect compiled output.
Common Errors
Practice Questions
What does the React Compiler do at build time? It analyzes component and hook bodies, infers which values are stable vs reactive, and inserts automatic memoization calls to prevent unnecessary re-renders.
How does the compiler handle intentional mutations like event handlers? Event handlers and refs are excluded from reactivity analysis. The compiler recognizes callback patterns and ref mutations as intentionally mutable and does not memoize them.
What is the
"use no memo"directive for? It tells the compiler to skip a specific scope (component, hook, or expression). Use it when the compiler's analysis is incorrect or when you need raw performance without memoization overhead.
Challenge
Create a component with 10 derived values computed from props. First, profile its render performance without any memoization. Then enable the React Compiler and compare render times. Next, manually add useMemo and useCallback to the same component and compare bundle size — the compiler version should be smaller and equally fast.
Real-World Task
Take the most frequently re-rendering component in your app (use React DevTools Profiler to find it). Remove all manual useMemo, useCallback, and React.memo calls. Enable the React Compiler. Profile again. Compare bundle size and render performance before and after.
Mini Project: Optimized Settings Page
Build a settings page with:
- 30+ toggle switches, dropdowns, and text inputs
- A search bar that filters settings in real time
- Theme color picker that updates the page live
- Run the React Compiler and measure interaction latency
Compare three versions: no memoization, hand-optimized with React.memo, and compiler-optimized.
Learning Path
flowchart LR A[React Hooks Complete Guide] --> B[React Performance Optimization] B --> C[React Compiler Explained] C --> D[React Concurrent Features] D --> E[React Server Actions] style C fill:#4a90d9,color:#fff
Next Steps
- Previous: React Performance Optimization — Memoization, Lazy Loading, and Profiling, React Hooks Deep Dive
- Next: React Server Actions Guide, React Concurrent Features Explained
- Related: React TypeScript — Using TypeScript with React, React State Management — Redux, Zustand, Context API Compared
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro. Durga Antivirus Pro's configuration panel uses this same auto-memoization approach — 40+ settings toggles re-render independently without any manual React.memo wrappers in the source code.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro