Static Validation & Safety
The React Compiler performs a series of static analysis passes to ensure that your code adheres to React’s rules and to optimize the resulting output. These validations prevent common anti-patterns and determine the minimal set of reactive scopes required for safe memoization.
Capitalized Call Validation
React reserves capitalized function names for components. Components must be invoked using JSX syntax (e.g., <MyComponent />) rather than direct function calls (e.g., MyComponent()). The compiler enforces this via the ValidateNoCapitalizedCalls pass.
Validation Rules
The compiler identifies identifiers that start with an uppercase letter and flags them if they are used in a CallExpression or MethodCall. This prevents issues where a component's lifecycle or hooks might be executed incorrectly.
An error is triggered if:
- A global capitalized variable is called as a function.
- A capitalized property is called as a method.
- A capitalized identifier is aliased to another variable and then called.
Configuration & Allowlisting
Certain globals and patterns are exempt from this rule. You can configure these in your environment settings.
- Default Allowlist: Built-in JavaScript constructors such as
Boolean,Number,String,Object,Array,Error, andPromiseare permitted. - Hook Pattern: The compiler uses a regex to identify hooks. If a capitalized call matches the
hookPattern(e.g.,React$useState), it is permitted. - Custom Allowlist: You can extend the allowed names via the
validateNoCapitalizedCallsarray in the compiler configuration.
// Example of a validation error
function Component() {
// ❌ Error: Capitalized functions are reserved for components
const x = SomeFunc();
// ✅ Correct: Rendered via JSX
return <SomeFunc />;
}
Escape Analysis and Scope Pruning
To optimize code size and execution overhead, the compiler performs Escape Analysis. This process determines which reactive scopes are necessary and which can be safely "pruned" (removed).
Criteria for Escaping
A value is considered to "escape" if it meets any of the following conditions:
- Direct Return: The value is returned by the function or transitively aliased by a return value.
- Hook Input: The value is passed as an argument to a hook. Because hooks may store references externally (e.g.,
useEffectclosures), the compiler treats these as escaping.
Dependency Tracking
Pruning is not based solely on whether a value escapes. The compiler also tracks transitive dependencies to maintain memoization stability:
- Downstream Invalidation: If a scope produces an escaping value (Value A), all of its dependencies (Value B) must also be memoized, even if Value B does not escape. If Value B were not memoized, it would recreate on every render, causing Value A's scope to invalidate unnecessarily.
- Interleaved Mutations: When multiple values are mutated within the same reactive scope, the entire scope is preserved if any of the produced values escape.
function Component(props) {
// 'a' does not escape, but it is a dependency of 'b'.
// It must be memoized to prevent 'b' from invalidating.
const a = [props.a];
// 'b' escapes via the return statement.
const b = [];
const c = {};
c.link = a;
b.push(props.b);
return b;
}
Memoization Safety Guarantees
The compiler includes specific validation flags to ensure that manual memoization (useMemo, useCallback) is handled safely or preserved when requested.
Preserving Existing Guarantees
When the @validatePreserveExistingMemoizationGuarantees directive is used, the compiler verifies that it does not prune or optimize away logic that was explicitly wrapped in manual memoization if that logic is required to maintain existing performance contracts.
Global Safety Checks
| Check | Description |
| :--- | :--- |
| Hook Pattern Enforcement | Ensures that any function following the use[A-Z] naming convention adheres to the Rules of Hooks. |
| No-Alias Validation | Ensures that non-escaping values are not accidentally aliased in a way that creates memory leaks or unexpected side effects. |
| Primitive Inlining | Identifies non-escaping, non-reactive primitives and inlines them to reduce temporary variable allocation. |
Error Reporting
When a validation fails, the compiler produces a CompilerError containing:
- Category: The type of violation (e.g.,
ErrorCategory.CapitalizedCalls). - Reason: A human-readable explanation of why the code is invalid.
- Location: The exact line and column in the source code.
- Suggestions: Guidance on how to refactor the code to satisfy the compiler (e.g., "rename to lowercase" or "invoke with JSX").