facebook/react · error

React Refresh Babel transform should only be enabled in deve

Error message

React Refresh Babel transform should only be enabled in development environment. Instead, the environment is: "${env}". If you want to override this check, pass {skipEnvCheck: true} as plugin options.

What it means

The react-refresh Babel plugin (ReactFreshBabelPlugin) refuses to run outside a development environment: if babel.env() returns anything other than 'development' and the plugin options do not include skipEnvCheck: true, it throws at build start. The check exists because the transform emits $RefreshReg$/$RefreshSig$ registration calls — development-only instrumentation that must never reach a production or test bundle.

Source

Thrown at packages/react-refresh/src/ReactFreshBabelPlugin.js:15

/**
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

'use strict';

export default function (babel, opts = {}) {
  if (typeof babel.env === 'function') {
    // Only available in Babel 7.
    const env = babel.env();
    if (env !== 'development' && !opts.skipEnvCheck) {
      throw new Error(
        'React Refresh Babel transform should only be enabled in development environment. ' +
          'Instead, the environment is: "' +
          env +
          '". If you want to override this check, pass {skipEnvCheck: true} as plugin options.',
      );
    }
  }

  const {types: t} = babel;
  const refreshReg = t.identifier(opts.refreshReg || '$RefreshReg$');
  const refreshSig = t.identifier(opts.refreshSig || '$RefreshSig$');

  const registrationsByProgramPath = new Map();
  function createRegistration(programPath, persistentID) {
    const handle = programPath.scope.generateUidIdentifier('c');
    if (!registrationsByProgramPath.has(programPath)) {
      registrationsByProgramPath.set(programPath, []);
    }

View on GitHub (pinned to eafeac097b)

Solutions

  1. Make the babel config a function and include 'react-refresh/babel' only when the env is development (api.env() === 'development' or process.env.NODE_ENV === 'development')
  2. With webpack, use @pmmmwh/react-refresh-webpack-plugin, which injects the Babel plugin only for mode: 'development'
  3. If you deliberately run the transform under a non-'development' env name (e.g. BABEL_ENV=test to compile a dev-mode playground), pass options: {skipEnvCheck: true}

Example fix

// before (.babelrc)
{ "plugins": ["react-refresh/babel"] }

// after (babel.config.js)
module.exports = function (api) {
  api.cache.using(() => process.env.NODE_ENV);
  return {
    plugins: [
      ...(process.env.NODE_ENV === 'development' ? ['react-refresh/babel'] : []),
    ],
  };
};
Defensive patterns

Strategy: validation

Validate before calling

// babel.config.js
module.exports = function (api) {
  api.cache.using(() => process.env.NODE_ENV);
  const isDev = process.env.NODE_ENV === 'development';
  return {plugins: [...(isDev ? ['react-refresh/babel'] : [])]};
};

Prevention

When it happens

Trigger: Listing 'react-refresh/babel' unconditionally in babel.config.js/.babelrc while BABEL_ENV or NODE_ENV resolves to 'production' or 'test'; a Metro or webpack production build inheriting the dev babel config unchanged; CI pipelines that reuse the dev babel config with NODE_ENV=test.

Common situations: One shared babel config for dev and prod (ejected CRA, custom webpack setups); manually adding Fast Refresh instead of using @pmmmwh/react-refresh-webpack-plugin; test runners that set BABEL_ENV=test and pull the plugin in through a preset chain.

Related errors


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