facebook/react · warning

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

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.

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.

Appendix: 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)