Monorepo Architecture
React uses a monorepo architecture to manage the core library alongside its various renderers, utilities, and build-time tools. This structure ensures that changes to the core reconciler are atomically synchronized with platform-specific packages like react-dom and react-native, as well as the React Compiler.
Package Organization
The repository is divided into several logical areas, primarily located in the packages/ and compiler/ directories. This separation allows React to remain platform-agnostic while providing specialized implementations for different environments.
Core and Renderers
react: The core API. It contains only the necessary logic to define components and hooks (e.g.,useState,useMemo,useEffect).react-dom: The entry point for web applications. It implements the DOM renderer and handles event normalization.react-reconciler: A shared internal package used to build custom renderers. It manages the "fiber" tree and the diffing algorithm.shared: Internal utility functions and constants shared across all packages.
The React Compiler
Located under compiler/packages/, the React Compiler (often referred to as "React Forget") is a build-time tool designed to automatically optimize React applications.
babel-plugin-react-compiler: The primary interface for developers. This Babel plugin transforms standard React code into an optimized version that automatically memoizes values and functions.- Relationship with Core: While the core React library provides the runtime semantics, the compiler uses a High-level Intermediate Representation (HIR) to analyze component logic. It identifies non-escaping values and prunes unnecessary reactive scopes to reduce re-renders without requiring manual
useMemooruseCallbackcalls.
Build Channels
React distributes its packages through different "channels" to balance stability with the need to test new features.
| Channel | Purpose | Stability | | :--- | :--- | :--- | | Latest | The version most users should use. Follows semver. | Stable | | Canary | Features that are adopted by Meta and other frameworks (like Next.js/Remix) before a formal release. | Release Candidate | | Experimental | Research and development (e.g., early versions of the compiler or new concurrent features). | Unstable |
The Compiler-Runtime Relationship
The monorepo structure is critical for the interplay between the React Compiler and the React runtime. The compiler relies on specific runtime behaviors to ensure that its optimizations are safe.
Static Analysis and Validation
The compiler performs several validation passes to ensure your code follows the "Rules of React." For example, the ValidateNoCapitalizedCalls pass prevents calling components as functions, which would break Hook state association:
// Valid: Rendered via JSX
<MyComponent />
// Invalid: Identified by the compiler as a potential error
MyComponent();
Automatic Memoization
The compiler analyzes the "escape" path of variables. If a variable does not escape the component (i.e., it is not returned, passed to a Hook, or stored in an object that is later returned), the compiler may prune its reactive scope to save memory and CPU cycles.
function Component(props) {
// The compiler identifies that 'a' does not escape.
// It can optimize the creation of 'b' without needing to
// explicitly memoize 'a'.
const a = [props.a];
const b = [];
b.push(props.b);
return b;
}
Consuming Packages
If you are building a standard React application, you generally only interact with the top-level packages:
{
"dependencies": {
"react": "latest",
"react-dom": "latest"
},
"devDependencies": {
"babel-plugin-react-compiler": "experimental"
}
}
By maintaining these tools in a single monorepo, the React team ensures that the code generated by the compiler is always compatible with the internal fiber architecture of the react package.