Skip to main content

Upgrade to Babel 8

Refer users to this document when upgrading to Babel 8 from Babel 7. If you are a plugin developer or integration developer, please also check migration guide for integration.

If you are upgrading from Babel 6, please check here for Babel 7 migration guide.

All of Babel

Node.js support

All Babel 8 packages require Node.js ^18.20.0 || ^20.17.0 || >=22.8.0.

We highly encourage you to use a newer version of Node.js (LTS v20) since the previous versions are not maintained. See nodejs/Release for more information.

This just means Babel itself won't run on older versions of Node. It can still output code that runs on old Node versions.

ESM only

Babel is now shipped in native ECMAScript modules. (#11701)

@babel/core requirements

All presets and plugins require @babel/core@^8.0.0 as peer dependency.

@babel/eslint-parser and @babel/eslint-plugin

The parser and plugin require eslint@^8.9.0 as peer dependency. (#15563)

Package Renames

The following packages has been renamed to -transform as they have reached Stage 4 (#15614). The rename process has been landed in Babel 7.22 so you can start the migration prior to the upgrade.

Babel 7Babel 8
@babel/plugin-proposal-async-generator-functions@babel/plugin-transform-async-generator-functions
@babel/plugin-proposal-class-properties@babel/plugin-transform-class-properties
@babel/plugin-proposal-class-static-block@babel/plugin-transform-class-static-block
@babel/plugin-proposal-duplicate-named-capturing-groups-regex@babel/plugin-transform-duplicate-named-capturing-groups-regex
@babel/plugin-proposal-dynamic-import@babel/plugin-transform-dynamic-import
@babel/plugin-proposal-export-namespace-from@babel/plugin-transform-export-namespace-from
@babel/plugin-proposal-json-strings@babel/plugin-transform-json-strings
@babel/plugin-proposal-logical-assignment-operators@babel/plugin-transform-logical-assignment-operators
@babel/plugin-proposal-nullish-coalescing-operator@babel/plugin-transform-nullish-coalescing-operator
@babel/plugin-proposal-numeric-separator@babel/plugin-transform-numeric-separator
@babel/plugin-proposal-object-rest-spread@babel/plugin-transform-object-rest-spread
@babel/plugin-proposal-optional-catch-binding@babel/plugin-transform-optional-catch-binding
@babel/plugin-proposal-optional-chaining@babel/plugin-transform-optional-chaining
@babel/plugin-proposal-private-methods@babel/plugin-transform-private-methods
@babel/plugin-proposal-private-property-in-object@babel/plugin-transform-private-property-in-object
@babel/plugin-proposal-unicode-property-regex@babel/plugin-transform-unicode-property-regex

Package Discontinued

@babel/runtime-corejs2

Please upgrade to @babel/runtime-corejs3 (#11751). After you install the new runtime, please set the corejs version to 3.

babel.config.json
{
"plugins": ["@babel/transform-runtime", {
- corejs: 2
+ corejs: 3
}]
}

@babel/plugin-syntax-import-assertions

The proposal evolved into import attributes, which now Babel supports parsing by default. You can remove @babel/plugin-syntax-import-assertions from your config, and replace the following patterns in your codebase:

input.js
- import value from "module" assert { type: "json" };
+ import value from "module" with { type: "json" };

Syntax plugins

The following syntax plugins are no longer needed, you can safely remove them from your config and node modules:

  • @babel/plugin-syntax-async-functions
  • @babel/plugin-syntax-async-generators
  • @babel/plugin-syntax-bigint
  • @babel/plugin-syntax-class-properties
  • @babel/plugin-syntax-class-static-block
  • @babel/plugin-syntax-dynamic-import
  • @babel/plugin-syntax-exponentiation-operator
  • @babel/plugin-syntax-export-extensions
  • @babel/plugin-syntax-export-namespace-from
  • @babel/plugin-syntax-import-meta
  • @babel/plugin-syntax-json-strings
  • @babel/plugin-syntax-logical-assignment-operators
  • @babel/plugin-syntax-module-string-names
  • @babel/plugin-syntax-nullish-coalescing-operator
  • @babel/plugin-syntax-numeric-separator
  • @babel/plugin-syntax-object-rest-spread
  • @babel/plugin-syntax-optional-catch-binding
  • @babel/plugin-syntax-optional-chaining
  • @babel/plugin-syntax-private-property-in-object
  • @babel/plugin-syntax-top-level-await
  • @babel/plugin-syntax-trailing-function-commas
  • @babel/plugin-syntax-unicode-sets-regex

The following plugins are discontinued and their functionality is not available anymore:

  • @babel/plugin-syntax-import-assertions. Use @babel/plugin-syntax-import-attributes instead, and see the @babel/parser section for more information.

Configuration Changes

@babel/core

medium

  • The root AMD/UMD/SystemJS options, namely moduleIds, getModuleId, moduleRoot, moduleId and filenameRelative are moved to plugin options (#5473, #12724).

    Migration: Move these options to the module plugin, for example, if you are using @babel/plugin-transform-modules-systemjs:

    babel.config.js
    module.exports = {
    plugins: [
    ['@babel/plugin-transform-modules-systemjs', {
    moduleIds: true,
    moduleRoot: 'myApp',
    getModuleId (name) {
    return name + "suffix";
    },
    }],
    ],
    };

    Adapt the example above if you are using @babel/plugin-transform-modules-amd or @babel/plugin-transform-modules-umd. You can start the migration prior to Babel 8.0.

    If you are using @babel/cli and passing --module-ids, --module-root and --module-id from command line, please create a Babel config babel.config.js and specify options there.

@babel/preset-env

high

medium

  • includes and excludes respect renamed package names (#15576)

    Migration: If includes or excludes contain any plugins mentioned in the Packages Renames section, change it to the new name. For example,

    babel.config.json
    {
    "presets": [[
    "@babel/preset-env",
    {
    - "includes": ["proposal-optional-chaining"]
    + "includes": ["transform-optional-chaining"]
    }
    ]]
    }

low

  • Remove uglify target (#12594)

    Migration: The uglify target had been deprecated since 7.0.0, if you still need this, use the forceAllTransforms option.

  • Removed syntax plugins can not be used in includes and excludes (#15810)

    Migration: You can safely remove them if you are using any of syntax plugins listed above in the includes and excludes options.

@babel/preset-react

medium

  • Remove useSpread and useBuiltIns options (#12593)

    Migration: Babel 8 always compiles JSX spread elements to object spread:

    input.jsx
    <div {...props}></div>
    // transforms to
    jsx("div", { ...props })

    If your app targets to modern browsers released after 2019, you can safely remove these options as object spread has less code footprint.

    If your code needs to run in an environment which doesn't support object spread, you can either use @babel/preset-env (recommended) or @babel/plugin-transform-object-rest-spread. If you want to transpile Object.assign down, you also need to enable @babel/plugin-transform-object-assign. In Babel 7.7.0, you can opt-in this behavior by using the useSpread option.

  • Type check input options (#12460)

    Migration: The preset will also report invalid option names. Refer to the docs and ensure valid usage.

low

  • Disallow filter option in automatic runtime (#15068)

    Migration: The filter option can only be used with the classic runtime. If you have switched to automatic runtime, you can safely remove this option. Otherwise please specify runtime: "classic".

@babel/preset-typescript

high

  • Remove isTSX and allExtensions options (#14955)

    Migration:

    • isTSX: true and allExtensions: true

      If you are already using @babel/preset-react, @babel/plugin-transform-react-jsx or any other third-party jsx presets such as @vue/babel-preset-jsx, and you want to transpile .tsx files, you can safely remove these two options. Babel 8 will automatically handle .tsx files using this preset and the other JSX plugin.

      babel.config.json
      {
      "presets": [
      ["@babel/preset-react", { "runtime": "automatic" }],
      - ["@babel/preset-typescript", { "allExtensions": true, "isTSX": true }]
      + ["@babel/preset-typescript"]
      ]
      }

      If you want to transpile files other than .tsx, such as .vue, use ignoreExtensions: true:

      babel.config.js
      {
      overrides: [{
      include: /\.vue$/,
      presets: [
      ['@babel/preset-typescript', {
      - allExtensions: true, isTSX: true
      + ignoreExtensions: true
      }]
      ]
      }]
      }

      If you want to preserve the JSX format but transpile the TypeScript part, use ignoreExtensions: true and add @babel/plugin-syntax-jsx to plugins.

    • isTSX: false and allExtensions: true

      Use ignoreExtensions: true, see the example above.

    • isTSX: false and allExtensions: false

      You can safely remove them.

medium

  • Remove allowDeclareFields option (#12461)

    Migration: Remove the option from your config, since it's now enabled by default. Previously allowDeclareFields enables transforming the declare syntax introduced in TypeScript 3.7, in Babel 8 we support the syntax without such a flag. See also the compilation changes section.

  • Type check input options (#12460)

    Migration: The preset will also report invalid option names. Refer to the docs and ensure valid usage. For example, runtime is not a valid preset-typescript option and thus should be removed.

@babel/plugin-transform-typescript

medium

  • Remove allowDeclareFields option (#12461)

    Migration: Remove the option from your config.

@babel/plugin-syntax-typescript

high

  • Remove isTSX option (#14955)

    Migration: If you are using isTSX: true, remove this option and add @babel/plugin-syntax-jsx to plugins:

    {
    "plugins": [
    - ["@babel/plugin-syntax-typescript", { "isTSX": true }]
    + ["@babel/plugin-syntax-typescript"]
    + ["@babel/plugin-syntax-jsx"]
    ]
    }

    If you are using isTSX: false, you can safely remove them.

@babel/preset-flow

medium

  • Remove allowDeclareFields option (#12457)

    Migration: Remove the option from your config, since it's now enabled by default. Previously allowDeclareFields enables transforming the declare syntax introduced in Flow 0.120.0, in Babel 8 we support the syntax without such a flag. See also the compilation changes section.

  • Remove enums option (#16792)

    Migration: Remove the option from your config. The enums option was used to enable Flow enums, which are now supported by default.

  • Type check input options (#12460)

    Migration: The preset will also report invalid option names. Refer to the docs and ensure valid usage.

@babel/plugin-transform-flow-strip-types

medium

  • Remove allowDeclareFields option (#12457)

    Migration: Remove the option from your config. You will probably be fine with the new behaviour.

  • Remove enums option (#16792)

    Migration: Remove the option from your config. The enums option was used to enable Flow enums, which are now supported by default.

@babel/parser

medium

  • Remove estree plugin option classFeatures (#13752)

    Migration: Remove the option from your config, since it's now enabled by default. Previously the classFeatures plugin enables @babel/parser to produce class properties AST compatible with ESLint 8, following the ESTree specification. In Babel 8 the eslint-parser only works with ESLint 8 and above.

    • Remove decimal plugin option #16741

    Migration: Migrate your project to the latest proposal and remove the plugin from your config since the latest proposal doesn't have syntax anymore.

    example.js
    - 1.03m
    + new Decimal("1.03")
    - decimal1 + decimal2
    + decimal1.add(decimal2)
  • Remove importAssertions parser plugin (#16770)

    This plugin was for an old version of the import attributes proposal, using the assert keyword instead of with. The proposal moved ahead without the assert keyword.

    Migration: Replace the plugin with importAttributes. If you are still using the assert keyword it's recommended that you migrate to with: if it's not possible to do so, you can use the ["importAttributes", { deprecatedAssertSyntax: true }] option.`

  • Remove importReflection parser plugin (#16808)

    The "import reflection" proposal does not exist anymore, and it was superseeded by the "source phase imports" proposal, which uses the source modifier for imports instead of module.

    Migration: Replace the plugin with sourcePhaseImports, and migrate your code to use source instead of module in import declarations.

@babel/generator

medium

  • Remove jsonCompatibleStrings generator option (#9943, #12477)

    Migration: @babel/generator allows to specify options for jsesc, a library used to escape printed values. If you are using the jsonCompatibleStrings option, you can replace it with jsescOption: { json: true }.

@babel/eslint-parser

medium

  • Remove allowImportExportEverywhere option (#13921)

    Migration: Use babelOptions.parserOpts.allowImportExportEverywhere instead.

    .eslintrc
    {
    "parser": "@babel/eslint-parser",
    "parserOptions": {
    - "allowImportExportEverywhere": true,
    + "babelOptions": {
    + "parserOpts": {
    + "allowImportExportEverywhere": true
    + }
    + }
    }
    }

low

  • parserOpts.allowSuperOutsideMethod defaults to false (#13921)

    Migration: If you want to restore to Babel 7 behaviour, set babelOptions.parserOpts.allowSuperOutsideMethod to true.

  • allowReturnOutsideFunction is inferred from ecmaFeatures.globalReturn (#13921)

    Migration: If you want to enable allowReturnOutsideFunction, set ecmaFeatures.globalReturn to true.

    .eslintrc
    {
    "parser": "@babel/eslint-parser",
    "parserOptions": {
    "ecmaFeatures": {
    "globalReturn": true
    }
    }
    }

@babel/plugin-transform-modules-systemjs

medium

  • Require @babel/plugin-transform-dynamic-import when transforming import() to SystemJS (#12700)

    Migration: Add @babel/plugin-transform-dynamic-import to your config: you can already do it in Babel 7. If you are using @babel/preset-env, you don't need to do anything.

    babel.config.js.diff
    {
    "plugins": [
    + "@babel/plugin-transform-dynamic-import",
    "@babel/plugin-transform-modules-systemjs",
    ]
    }

    Notes: All the other plugins which support dynamic import (transform-modules-commonjs and transform-modules-amd) require the separate plugin since it was introduced. We couldn't change it for transform-modules-systemjs because that package did already support dynamic import.

@babel/plugin-proposal-decorators

medium

  • Only support legacy and 2023-11. The plugin now requires a version option (#12712, #15676)

    Migration: You should migrate to the latest version of the proposal "2023-11", if you are using the "2018-09" or you have not specified a version option.

    babel.config.json
    {
    "plugins": [
    ["@babel/plugin-proposal-decorators", {
    - "decoratorsBeforeExport": true,
    - "version": "2018-09",
    + "version": "2023-11"
    }]
    ]
    }

    The syntax is the same, but you will need to rewrite your decorator functions. The spec repo provides comparison between the latest version and the 2018-09 version. You can already migrate since Babel 7.22.0, using the "version": "2023-05" option of @babel/plugin-proposal-decorators.

    Although Babel 8 still supports the legacy version, it is advisable to migrate to the 2023-05 version regardless: both Babel 8 and TypeScript 5.0 support the 2023-05 version, while there are a few behaviour differences in the legacy version between Babel and tsc's implementation.

@babel/plugin-transform-runtime

medium

low

  • The useESModules option has been removed (#16141)

    Migration: Delete it from your configuration. @babel/runtime will now automatically expose ES modules when needed, using package.json#exports.

  • The runtime and helpers options have been removed (#16311)

    Migration: Delete them from your configuration: @babel/runtime will now always import helpers. If you don't want to inject imports to helpers, remove @babel/plugin-transform-runtime from your config.

@babel/node

low

  • The -gc and -d command-line flags have been removed (#15956) Migration: Use the --expose-gc and --inspect Node.js flags respectively. Note that although -d was short for --debug, the latter has been deprecated since Node.js 7.7.0.

  • Command-line flags for Node.js and Babel must now be passed before the filename, while flags for the script itself must be passed after. (#16706)

Compilation Changes

Default target

medium

@babel/preset-env

low

  • Enable the bugfixes option by default (#13866)

    Migration: You will probably be fine with the new behaviour as Babel now tries to compile the broken syntax to the closest non-broken modern syntax supported by your target browsers. If anyhow you want to restore the Babel 7 behaviour, you can specify bugfixes: false.

JSX

high

  • Use the new JSX implementation by default (#12630)

    Migration: If you are using a modern version of React or Preact, it should work without any configuration changes. Otherwise, you can pass the runtime: "classic" option to @babel/preset-react or @babel/plugin-transform-react-jsx to be explicit about your usage of createElement (or the equivalent function in other libraries).

medium

low

  • Disallow sequence expressions inside JSX attributes (#12447)

    Migration: Find and replace the following code patterns. You can start the migration prior to Babel 8:

    input.jsx
    - <p key={foo, bar}></p> // Invalid
    + <p key={(foo, bar)}></p> // Valid
  • Disallow {, }, < and > in JSX text (#12451)

    Migration: Use {'{'}, {'}'}, {'<'} and {'>'} instead. Find and replace the following code patterns. You can start the migration prior to Babel 8:

    input.jsx
    - <p>">" is greater than.</p>
    + <p>"{'>'}" is greater than.</p>

    Notes: This is technically a spec compliance fix becase the JSX specification already forbids them. However, we have chosen to postpone it until Babel 8 because it could break someone's code.

TypeScript

high

  • Preserve uninitialized class fields (#12461)

    Migration: Use the new declare syntax, introduced in TypeScript 3.7, if you don't want fields to be initialized to undefined:

    input.ts
    class A {
    foo: string | void; // initialized to undefined
    declare bar: number; // type-only, will be removed
    }

Flow

high

  • Preserve uninitialized class fields (#12457)

    Migration: Use the new declare syntax, introduced in Flow 0.120, if you don't want fields to be initialized to undefined:

    input.js
    class A {
    foo: string | void; // initialized to undefined
    declare bar: number; // type-only, will be removed
    }

Misc

low

  • Output non-ASCII characters as-is in string literal (#12675)

    If you are using any one of @babel/cli, WebPack, Rollup, create-react-app or other Node.js powered bundlers, the transformed code is always encoded with utf-8 and your app will not be affected. The issue only affects if you are manually calling the babel.transform API and your web server is not serving js files in the utf8 encoding.

    Migration: Ensure your server is always serving js files in the utf8 encoding. If you can not control the server output, specify the charset attribute of the script tag in the html files.

    <script charset="utf-8" src="your-app.js"></script>

    You can also restore to the Babel 7 behaviour by

    babel.config.js
    {
    generatorOpts: {
    jsescOption: {
    minimal: false
    }
    }
    }