facebook/react · critical

React Refresh runtime should not be included in the producti

Error message

React Refresh runtime should not be included in the production bundle.

What it means

react-refresh/runtime (ReactFreshRuntime) throws at module-evaluation time when it is compiled with __DEV__ === false. The runtime maintains the module registry and patches React's internals purely for Fast Refresh; shipping it in a production bundle is always a bundling mistake, so the module hard-fails on load instead of silently bloating (or breaking) the production artifact.

Source

Thrown at packages/react-refresh/src/ReactFreshRuntime.js:36

import type {ReactNodeList} from 'shared/ReactTypes';

import {REACT_MEMO_TYPE, REACT_FORWARD_REF_TYPE} from 'shared/ReactSymbols';

type Signature = {
  ownKey: string,
  forceReset: boolean,
  fullKey: string | null, // Contains keys of nested Hooks. Computed lazily.
  getCustomHooks: () => Array<Function>,
};

type RendererHelpers = {
  scheduleRefresh: ScheduleRefresh,
  scheduleRoot: ScheduleRoot,
  setRefreshHandler: SetRefreshHandler,
};

if (!__DEV__) {
  throw new Error(
    'React Refresh runtime should not be included in the production bundle.',
  );
}

// In old environments, we'll leak previous types after every edit.
const PossiblyWeakMap = typeof WeakMap === 'function' ? WeakMap : Map;

// We never remove these associations.
// It's OK to reference families, but use WeakMap/Set for types.
const allFamiliesByID: Map<string, Family> = new Map();
const allFamiliesByType: WeakMap<any, Family> | Map<any, Family> =
  new PossiblyWeakMap();
const allSignaturesByType: WeakMap<any, Signature> | Map<any, Signature> =
  new PossiblyWeakMap();
// This WeakMap is read by React, so we only put families
// that have actually been edited here. This keeps checks fast.
const updatedFamiliesByType: WeakMap<any, Family> | Map<any, Family> =
  new PossiblyWeakMap();

View on GitHub (pinned to eafeac097b)

Solutions

  1. Gate every react-refresh import and setup call behind if (process.env.NODE_ENV !== 'production')
  2. Use the official integrations (@pmmmwh/react-refresh-webpack-plugin or framework defaults), which exclude the runtime from production builds
  3. Verify the fix by grepping the prod bundle for 'React Refresh runtime should not be included' — zero hits expected
  4. Move react-refresh to devDependencies so a prod reference fails at install time rather than at runtime

Example fix

// before (entry.js, always executed)
require('react-refresh/runtime');
require('react-refresh/runtime').injectIntoGlobalHook(window);

// after
if (process.env.NODE_ENV !== 'production') {
  const refresh = require('react-refresh/runtime');
  refresh.injectIntoGlobalHook(window);
}
Defensive patterns

Strategy: validation

Validate before calling

if (process.env.NODE_ENV !== 'production') {
  const refresh = require('react-refresh/runtime');
  refresh.injectIntoGlobalHook(window);
}

Prevention

When it happens

Trigger: A production build that imports react-refresh/runtime — for example bootstrap code like `if (module.hot) { require('react-refresh/runtime'); ... }` where the guard does not also exclude prod; the bundler resolving __DEV__ to false (correct) while the module itself still gets included via an unconditional import in a shared entry file.

Common situations: Manually wiring Fast Refresh in custom webpack/esbuild setups without the official plugin's prod gating; a shared setup file (app bootstrap, jest setup) imported into the production entry; stale bundle cache where a dev-only import leaked into a prod artifact.

Related errors


AI-assisted analysis of facebook/react@eafeac097b (2026-08-21). Data as JSON: /api/errors/cac7f4292e43a9c1. Report an issue: GitHub.