Open-Source Wikis

/

React

/

Reference

/

Configuration

facebook/react

Configuration

The runtime is configured along two axes: release channels (which set of feature flags is enabled) and bundle types (development vs production, ESM vs CJS vs UMD, etc.). Both are coordinated by scripts/rollup/build.js.

Release channels

A release channel is a per-build override of packages/shared/ReactFeatureFlags.js. Each channel has its own fork file in packages/shared/forks/ that re-exports the same flag names with potentially different defaults. The Rollup build picks the right fork based on the channel currently being built.

Channel Forks file Notes
stable (uses ReactFeatureFlags.js directly) What ships as react@latest on npm.
experimental ReactFeatureFlags.js flags gated on __EXPERIMENTAL__ What ships as react@experimental on npm.
next-major (transient experimental subset) Used for testing the next major version's behavior.
www-classic packages/shared/forks/ReactFeatureFlags.www.js (with disableLegacyMode = false) Facebook's legacy synchronous-mode codepath.
www-modern packages/shared/forks/ReactFeatureFlags.www.js (with disableLegacyMode = true) Facebook's concurrent-mode codepath.
www-dynamic packages/shared/forks/ReactFeatureFlags.www-dynamic.js Variant of www where some flags are evaluated at runtime via Facebook's gating system.
test-renderer packages/shared/forks/ReactFeatureFlags.test-renderer.js What react-test-renderer runs against.
test-renderer.www packages/shared/forks/ReactFeatureFlags.test-renderer.www.js Test renderer with www flags.
test-renderer.native-fb packages/shared/forks/ReactFeatureFlags.test-renderer.native-fb.js Test renderer with native flags.
native-oss packages/shared/forks/ReactFeatureFlags.native-oss.js React Native open-source channel.
native-fb packages/shared/forks/ReactFeatureFlags.native-fb.js React Native FB-internal channel.
native-fb-dynamic packages/shared/forks/ReactFeatureFlags.native-fb-dynamic.js Native FB with runtime gating.
eslint-plugin.www packages/shared/forks/ReactFeatureFlags.eslint-plugin.www.js The eslint plugin's view of www flags.
readonly packages/shared/forks/ReactFeatureFlags.readonly.js Shim for tools that import flags but should never see real values.

The yarn flags script (= node ./scripts/flags/flags.js) prints a matrix of every flag and its value per channel.

Feature flags

packages/shared/ReactFeatureFlags.js is the single source of truth for what flags exist. The file is organized into thematic sections, each commented with a name like:

  • Land or remove (zero effort) — flags ready to be deleted or made permanent.
  • Killswitch — flags that exist purely as escape hatches; should be removed once a feature has shipped without regressions.
  • Slated for removal in the future (significant effort) — abandoned experiments waiting for callers to migrate.
  • Ongoing experiments — features actively being developed.
  • Profiling — flags controlling perf instrumentation.

Examples of long-running flags (as of this snapshot):

export const disableSchedulerTimeoutInWorkLoop = false;
export const enableSuspenseCallback = false;
export const enableScopeAPI = false;
export const enableCreateEventHandleAPI = false;
export const enableLegacyFBSupport = false;
export const enableYieldingBeforePassive = false;
export const enableThrottledScheduling = false;
export const enableLegacyCache = __EXPERIMENTAL__;
export const enableAsyncIterableChildren = __EXPERIMENTAL__;
export const enableTaint = __EXPERIMENTAL__;

The pattern = __EXPERIMENTAL__ is shorthand for "on in experimental, off in stable". The Rollup replace plugin substitutes __EXPERIMENTAL__ with a literal true or false per channel, so the dead branch is dead-code-eliminated.

Lifecycle of a flag

  1. Add in ReactFeatureFlags.js with default false.
  2. Gate all new code on it.
  3. Test both branches with @gate (see how-to-contribute/testing).
  4. Flip in experimental by setting it to true in ReactFeatureFlags.js (under the = __EXPERIMENTAL__ shorthand) or in the experimental fork.
  5. Bake for several weeks of nightly prereleases.
  6. Flip in stable by hardcoding to true in ReactFeatureFlags.js.
  7. Bake for at least one stable release.
  8. Delete the flag and its dead branch.

A surprising number of flags spend years in steps 4–6.

Globals injected at build time

scripts/rollup/build.js configures Rollup's replace plugin to substitute these strings:

Global Substituted with
__DEV__ true in development bundles, false in production.
__PROFILE__ true in profiling bundles, false otherwise. Profiling bundles are dev bundles with Performance API instrumentation kept in.
__EXPERIMENTAL__ true in the experimental channel, false elsewhere.
__VARIANT__ true in variant builds (rarely used).
__TEST__ true during Jest runs.
process.env.NODE_ENV "development" or "production" per build.

__DEV__ is by far the most common — every warning and console.error dev-only message is wrapped in if (__DEV__) { ... } so the production bundle dead-code-eliminates them.

Bundle types

scripts/rollup/build.js produces bundles in many shapes. The relevant constants are at the top of the file. Common types:

Type Purpose
UMD_DEV / UMD_PROD UMD bundles for <script> tags (e.g. unpkg.com/react).
NODE_DEV / NODE_PROD CommonJS bundles for Node.js. The default for the npm package.
NODE_PROFILING Production CJS with profiling APIs preserved.
ESM_DEV / ESM_PROD Native ESM bundles.
BUN_DEV / BUN_PROD Bun-targeted bundles.
FB_WWW_DEV / FB_WWW_PROD / FB_WWW_PROFILING Facebook internal bundles.
RN_OSS_DEV / RN_OSS_PROD / RN_OSS_PROFILING React Native open-source bundles.
RN_FB_DEV / RN_FB_PROD / RN_FB_PROFILING React Native Facebook-internal bundles.
NODE_ES2015 A modern-syntax CJS bundle, used by the react-server condition path.

Each bundles[].bundleTypes array in scripts/rollup/bundles.js declares which of these to produce.

Versioning

ReactVersions.js at the repo root is the source of truth for per-package versions. The file declares each package's version and its prerelease channel suffix. The script scripts/tasks/version-check.js (= yarn version-check) verifies that every packages/<pkg>/package.json agrees with this central file.

packages/shared/ReactVersion.js is generated from ReactVersions.js at build time and is what the published bundles import for React.version.

JSX configuration

The JSX runtime is built per-channel as part of react. The default Babel config at the repo root is babel.config.js. Variants:

  • babel.config-ts.js — TypeScript-specific config used by the compiler workspace.
  • babel.config-react-compiler.js — config used when compiling fixtures with the React Compiler.

react/jsx-runtime, react/jsx-dev-runtime, and their .react-server.js siblings are tiny shims that re-export from packages/react/src/jsx/.

Lint and Flow configuration

  • .eslintrc.js — ESLint config, including the React-internal plugin in scripts/eslint-rules/.
  • .eslintignore, .prettierignore — ignored paths.
  • .prettierrc.js — Prettier config (Prettier 3 default + a couple of repo-wide overrides).
  • flow-typed.config.json and flow-typed/ — Flow library definitions.
  • scripts/flow/createFlowConfigs.js — generates per-renderer .flowconfig files at yarn install time.

Per-package package.json configuration

Most packages declare a long exports map with a react-server condition:

{
  "name": "react",
  "exports": {
    ".": {
      "react-server": "./react.react-server.js",
      "default": "./index.js"
    },
    "./jsx-runtime": {
      "react-server": "./jsx-runtime.react-server.js",
      "default": "./jsx-runtime.js"
    }
  }
}

The react-server condition is what lets react/react-dom expose a different surface in RSC contexts. Every public package's package.json is templated by packages/<pkg>/npm/ — the npm/ directory is what gets actually published, with versions and dependencies rewritten by scripts/release/.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Configuration – React wiki | Factory