compilationMode
The compilationMode option controls how the React Compiler selects which functions to compile.
{ compilationMode: 'infer' // or 'annotation', 'syntax', 'all' }
Reference
compilationMode
Controls the strategy for determining which functions the React Compiler will optimize.
Type
'infer' | 'syntax' | 'annotation' | 'all'
Default value
'infer'
Options
-
'infer'(default): The compiler uses intelligent heuristics to identify React components and hooks:- Functions explicitly annotated with
"use memo"directive - Functions that are named like components (PascalCase) or hooks (
useprefix) AND create JSX and/or call other hooks
- Functions explicitly annotated with
-
'annotation': Only compile functions explicitly marked with the"use memo"directive. Ideal for incremental adoption. -
'syntax': Only compile components and hooks that use Flow’s component and hook syntax. -
'all': Compile all top-level functions. Not recommended as it may compile non-React functions.
Caveats
- The
'infer'mode requires functions to follow React naming conventions to be detected - Using
'all'mode may negatively impact performance by compiling utility functions - The
'syntax'mode requires Flow and won’t work with TypeScript - Regardless of mode, functions with
"use no memo"directive are always skipped
Usage
Default inference mode
The default 'infer' mode works well for most codebases that follow React conventions:
{ compilationMode: 'infer' }
With this mode, these functions will be compiled:
// ✅ Compiled: Named like a component + returns JSX function Button(props) { return <button>{props.label}</button>; } // ✅ Compiled: Named like a hook + calls hooks function useCounter() { const [count, setCount] = useState(0); return [count, setCount]; } // ✅ Compiled: Explicit directive function expensiveCalculation(data) { "use memo"; return data.reduce(/* ... */); } // ❌ Not compiled: Not a component/hook pattern function calculateTotal(items) { return items.reduce((a, b) => a + b, 0); }
Incremental adoption with annotation mode
For gradual migration, use 'annotation' mode to only compile marked functions:
{ compilationMode: 'annotation' }
Then explicitly mark functions to compile:
// Only this function will be compiled function ExpensiveList(props) { "use memo"; return ( <ul> {props.items.map(item => ( <li key={item.id}>{item.name}</li> ))} </ul> ); } // This won't be compiled without the directive function NormalComponent(props) { return <div>{props.content}</div>; }
Using Flow syntax mode
If your codebase uses Flow instead of TypeScript:
{ compilationMode: 'syntax' }
Then use Flow’s component syntax:
// Compiled: Flow component syntax component Button(label: string) { return <button>{label}</button>; } // Compiled: Flow hook syntax hook useCounter(initial: number) { const [count, setCount] = useState(initial); return [count, setCount]; } // Not compiled: Regular function syntax function helper(data) { return process(data); }
Opting out specific functions
Regardless of compilation mode, use "use no memo" to skip compilation:
function ComponentWithSideEffects() { "use no memo"; // Prevent compilation // This component has side effects that shouldn't be memoized logToAnalytics('component_rendered'); return <div>Content</div>; }
Troubleshooting
Component not being compiled in infer mode
In 'infer' mode, ensure your component follows React conventions:
// ❌ Won't be compiled: lowercase name function button(props) { return <button>{props.label}</button>; } // ✅ Will be compiled: PascalCase name function Button(props) { return <button>{props.label}</button>; } // ❌ Won't be compiled: doesn't create JSX or call hooks function useData() { return window.localStorage.getItem('data'); } // ✅ Will be compiled: calls a hook function useData() { const [data] = useState(() => window.localStorage.getItem('data')); return data; }