facebook/react · warning

Your app (or one of its dependencies) is using an outdated J

Error message

Your app (or one of its dependencies) is using an outdated JSX transform. Update to the modern JSX transform for faster performance: https://react.dev/link/new-jsx-transform

What it means

In dev, createElement checks whether its config object contains __self but no key (ReactJSXElement.js:648). __self/__source are injected by the classic JSX transform's Babel development plugins; the modern automatic transform emits jsx(...) calls that never set __self, and the rare automatic-transform fallback to createElement always includes a key - which is why 'key' in config suppresses the check. Seeing __self therefore means some module in the bundle was compiled with the pre-React-17 classic transform.

Source

Thrown at packages/react/src/jsx/ReactJSXElement.js:648

  // Reserved names are extracted
  const props = {};

  let key = null;

  if (config != null) {
    if (__DEV__) {
      if (
        !didWarnAboutOldJSXRuntime &&
        '__self' in config &&
        // Do not assume this is the result of an oudated JSX transform if key
        // is present, because the modern JSX transform sometimes outputs
        // createElement to preserve precedence between a static key and a
        // spread key. To avoid false positive warnings, we never warn if
        // there's a key.
        !('key' in config)
      ) {
        didWarnAboutOldJSXRuntime = true;
        console.warn(
          'Your app (or one of its dependencies) is using an outdated JSX ' +
            'transform. Update to the modern JSX transform for ' +
            'faster performance: https://react.dev/link/new-jsx-transform',
        );
      }
    }

    if (hasValidKey(config)) {
      if (enableOptimisticKey && config.key === REACT_OPTIMISTIC_KEY) {
        key = REACT_OPTIMISTIC_KEY;
      } else {
        if (__DEV__) {
          checkKeyStringCoercion(config.key);
        }
        key = '' + config.key;
      }
    }

View on GitHub (pinned to eafeac097b)

Solutions

  1. Switch the app compiler to the automatic runtime: Babel preset-react {runtime:'automatic'}, TypeScript jsx:'react-jsx', esbuild --jsx=automatic, SWC runtime:'automatic'
  2. Identify the offending module in dev (the component/stack near the warning) and update or rebuild that dependency with the automatic transform
  3. Report to the package maintainer if a dependency ships classic-transformed code - it should publish untransformed JSX or use the automatic runtime

Example fix

// before: tsconfig.json
{ "compilerOptions": { "jsx": "react" } }

// after
{ "compilerOptions": { "jsx": "react-jsx" } }
Defensive patterns

Strategy: validation

Validate before calling

// scripts/check-jsx-transform.mjs - fail CI if classic-transform output ships
import {readFileSync, existsSync} from 'node:fs';

for (const file of ['dist/bundle.js']) {
  if (!existsSync(file)) continue;
  const code = readFileSync(file, 'utf8');
  if (code.includes('__self:') || /,\s*__self\s*=/.test(code)) {
    throw new Error(
      `${file}: classic JSX transform detected - build with the automatic runtime`,
    );
  }
}

Prevention

When it happens

Trigger: Any dependency or app module compiled with @babel/preset-react without runtime:'automatic' (or tsconfig jsx:'react', esbuild --jsx=transform, classic SWC settings) running in development mode, so Babel injects __self into the createElement config.

Common situations: Upgrading React 16 to 17+/18/19 without touching compiler settings; node_modules packages shipping unminified classic-transform output; custom esbuild/SWC pipelines still configured for classic JSX.

Related errors


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