# SWC Compatibility Transforms for Older JavaScript Versions: The Complete Guide

> Explore SWC compatibility transforms for older JavaScript versions. Downgrade modern ECMAScript syntax to ES2022 down to ES3 with SWC's powerful tools. Read the complete guide.

- Repository: [swc/swc](https://github.com/swc-project/swc)
- Tags: how-to-guide
- Published: 2026-06-15

---

**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`](https://github.com/swc-project/swc/blob/main/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:

```javascript
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:

```javascript
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`](https://github.com/swc-project/swc/blob/main/Cargo.toml):

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

```

Then use the transform in your pipeline:

```rust
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`](https://github.com/swc-project/swc/blob/main/lib.rs)** – Re-exports all versioned compatibility modules (`es2015`, `es2020`, etc.) and exposes the feature-gated `es3` module.
- **[`class_fields_use_set.rs`](https://github.com/swc-project/swc/blob/main/class_fields_use_set.rs)** – Implements the class fields transform used by ES2022 and newer editions.
- **[`reserved_words.rs`](https://github.com/swc-project/swc/blob/main/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`](https://github.com/swc-project/swc/blob/main/es2015_arrow.rs), [`es2020_nullish_coalescing.rs`](https://github.com/swc-project/swc/blob/main/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`](https://github.com/swc-project/swc/blob/main/class_fields_use_set.rs) and [`reserved_words.rs`](https://github.com/swc-project/swc/blob/main/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`](https://github.com/swc-project/swc/blob/main/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`](https://github.com/swc-project/swc/blob/main/tests/es2015_arrow.rs), while nullish coalescing logic is tested in [`tests/es2020_nullish_coalescing.rs`](https://github.com/swc-project/swc/blob/main/tests/es2020_nullish_coalescing.rs). The main entry point is [`src/lib.rs`](https://github.com/swc-project/swc/blob/main/src/lib.rs), which re-exports all version-specific modules.