SWC Compatibility Transforms for Older JavaScript Versions: The Complete Guide

SWC provides dedicated compatibility transforms via the swc_ecma_transforms_compat crate that downgrades modern ECMAScript syntax to older versions, supporting targets from ES2022 down to ES3 through version-specific modules.

The SWC compiler (speedy web compiler) provides a robust compatibility layer for transpiling modern JavaScript to legacy environments. Located in the swc-project/swc repository, the swc_ecma_transforms_compat crate organizes transforms into version-specific modules that map directly to ECMAScript edition features, enabling precise control over your output target.

How SWC Structures Compatibility Transforms

The compatibility system lives in crates/swc_ecma_transforms_compat and re-exports a hierarchy of modules—one per ECMAScript edition. Each module exposes transformation functions that rewrite modern syntax into compatible constructs for older runtimes.

When the es3 feature flag is enabled, the library provides an ES3-compatible layer; otherwise, the highest supported target is ES5. When no explicit target is requested, SWC defaults to the highest-available transform that matches your compilation needs.

Version-Specific Transform Modules

SWC organizes compatibility transforms by ECMAScript edition, allowing you to target specific language versions selectively.

ES2022 Compatibility

The es2022 module handles class fields and private fields, static blocks, import.meta, and logical assignment operators (&&=, ||=, ??=). The implementation leverages class_fields_use_set.rs for transforming private field syntax.

ES2021 Compatibility

The es2021 module transforms logical assignment operators, String.prototype.replaceAll, and Promise.any into compatible syntax for older environments.

ES2020 Compatibility

The es2020 module handles nullish coalescing (??), optional chaining (?.), BigInt, and dynamic import(). These transforms rewrite modern syntax into conditional expressions and function calls that work in pre-2020 runtimes.

ES2019 Compatibility

The es2019 module transforms optional catch binding, Object.fromEntries, and array methods like flat and flatMap into ES2018-compatible equivalents.

ES2018 Compatibility

The es2018 module transpiles asynchronous iteration (for-await…of) and rest/spread properties for objects into generator-based or Object.assign patterns.

ES2017 Compatibility

The es2017 module converts async functions to generators (async → function*) and handles transforms for Object.entries and Object.values.

ES2016 Compatibility

The es2016 module transforms the exponentiation operator (**) into equivalent Math.pow calls.

ES2015 (ES6) Compatibility

The es2015 module is the most comprehensive, handling arrow functions, classes, template literals, destructuring, default parameters, let/const block scoping, for-of, computed property names, shorthand properties, spread operator, and Symbol.

ES5 and ES3 Compatibility

When no specific target is selected, SWC defaults to ES5-compatible output. The optional es3 module (enabled via the es3 feature flag) further transforms code to support property literals, legacy octal literals, var-only scoping, and removal of const/let declarations.

Implementing Compatibility Transforms in Your Build Pipeline

You can invoke these transforms through the JavaScript API or directly in Rust.

Node.js API Usage

Apply the ES2015 transform using the @swc/core package:

const { transformSync } = require("@swc/core");

const output = transformSync(sourceCode, {
  jsc: {
    target: "es5",
    parser: { syntax: "ecmascript" },
    transform: {
      es2015: require("swc_ecma_transforms_compat").es2015,
    },
  },
  module: { type: "commonjs" },
});

Targeting Specific Features

For granular control, import specific transforms like the ES2020 nullish coalescing shim:

const output = transformSync(source, {
  jsc: {
    target: "es2019",
    transform: {
      nullish_coalescing: require("swc_ecma_transforms_compat")
        .es2020
        .nullish_coalescing(),
    },
  },
});

Rust Implementation with Feature Flags

To enable ES3 support in a Rust project, add the feature flag in your Cargo.toml:

[dependencies]
swc_ecma_transforms_compat = { version = "0.123", features = ["es3"] }

Then use the transform in your pipeline:

use swc_ecma_transforms_compat::es3;

let transformed = es3::es3(cm, Default::default(), Default::default())?;

Key Source Files and Implementation Details

The implementation resides in crates/swc_ecma_transforms_compat/src/:

  • lib.rs – Re-exports all versioned compatibility modules (es2015, es2020, etc.) and exposes the feature-gated es3 module.
  • class_fields_use_set.rs – Implements the class fields transform used by ES2022 and newer editions.
  • reserved_words.rs – Handles reserved-word edge cases when targeting older ECMAScript versions.
  • tests/ – Contains concrete test snapshots for each compatibility transform (e.g., es2015_arrow.rs, es2020_nullish_coalescing.rs).

Summary

  • SWC's compatibility transforms are organized in the swc_ecma_transforms_compat crate with dedicated modules for each ECMAScript version from ES2022 to ES3.
  • Each module exports specific transformation functions that downgrade modern syntax to legacy equivalents.
  • The es3 feature flag enables support for ES3 environments, while ES5 is the default lowest target.
  • Implementation files like class_fields_use_set.rs and reserved_words.rs handle specific edge cases in the transformation process.
  • You can invoke transforms via the JavaScript API or directly in Rust, with granular control over individual features.

Frequently Asked Questions

What is the default ECMAScript target for SWC compatibility transforms?

When no specific target is requested, SWC defaults to ES5-compatible output. The library automatically selects the highest-available transform that matches the feature set of your current compilation, downgrading newer syntax to ES5 constructs unless you specify a higher target or enable the es3 feature flag.

How do I enable ES3 compatibility in SWC?

ES3 support requires enabling the es3 feature flag in your Rust dependencies. Add features = ["es3"] to your swc_ecma_transforms_compat dependency in Cargo.toml, then import the es3 module. This transforms property literals, legacy octal literals, and restricts scoping to var declarations only.

Can I use SWC compatibility transforms with TypeScript?

Yes, the swc_ecma_transforms_compat crate works with TypeScript sources when configured correctly. Set the parser syntax to "typescript" in your SWC configuration, and the compatibility transforms will process the transpiled JavaScript output, downgrading it to your specified target version.

Where are the individual transform implementations located?

Each transform has dedicated source files and test suites within crates/swc_ecma_transforms_compat/. For example, arrow function transforms reside in tests/es2015_arrow.rs, while nullish coalescing logic is tested in tests/es2020_nullish_coalescing.rs. The main entry point is src/lib.rs, which re-exports all version-specific modules.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →