cheat sheet
oxc-transform
Package-level reference for oxc-transform on npm — Rust transformer from the oxc toolchain, TS/JSX support, current API maturity, and place in the ecosystem.
oxc-transform
What it is
oxc-transform is the transformer slice of the oxc (Oxidation Compiler) toolchain — a Rust rewrite of the entire JavaScript ecosystem (parser, linter, formatter, transformer, eventually resolver and bundler) led by Boshen and the oxc team. The transformer turns TypeScript and JSX into vanilla JavaScript using a Rust implementation that's measured at 5–10× faster than SWC and 50–100× faster than the TypeScript compiler.
oxc-transform is the npm-published binding to the transformer subset. It exposes a small JS API: feed it a string of TS/JSX, get back a string of JS. It does not bundle, does not resolve imports, and does not type-check — it's a transformer, like @babel/transform or swc's transform mode. Bundling sits in rolldown (which uses oxc's parser internally).
Caveat: the entire oxc toolchain is pre-1.0. The oxc-transform package surface is small enough to be reasonably stable, but the JS API has shifted between minors and may keep shifting until a 1.0 freeze. Treat as experimental for any production-critical path.
Install
# Project-local — pin exact version
npm install -D oxc-transform
pnpm add -D oxc-transform
yarn add -D oxc-transform
Output: oxc-transform ships pre-built native binaries per platform via optional deps; no Rust toolchain needed on consumer machines.
Other oxc packages typically installed together:
npm install -D oxc-parser oxc-resolver
Output: oxc-parser is the standalone parser; oxc-resolver is the module resolution layer. All three share a similar API style.
Versioning & Node support
- Pre-1.0
0.xline. Each minor can include breaking API changes. - Requires Node 18 or newer.
- Always pin exact versions; do not use caret ranges.
- Underlying binary built per platform; if your CI / target lacks a published binary, the install fails — keep an eye on the published
@oxc/<platform>-<arch>optional deps. - Active development; expect surface area to grow rather than shrink (e.g. new options for emit, decorators metadata, JSX runtime variations).
Package metadata
- Maintainers: oxc team (Boshen et al.) under the oxc-project org
- Project home: github.com/oxc-project/oxc
- Docs: oxc.rs
- npm: npmjs.com/package/oxc-transform
- License: MIT
- First released: 2024
- Downloads: modest; growth is mostly transitive via tooling that embeds oxc internally.
Peer dependencies & extras
oxc-transform has zero peers. Companion packages within the oxc ecosystem:
| Package | Role |
|---|---|
oxc-parser | The standalone JS/TS parser. Returns an AST as JSON-style Node objects. |
oxc-resolver | Rust port of Node's module resolution algorithm. |
oxc-minify | Minifier (in active development; may merge into oxc-transform). |
eslint-plugin-oxlint | The oxc linter (oxlint) as an ESLint plugin for gradual migration. |
@oxc-project/runtime | Helper functions for some transforms (e.g. decorator metadata, async iter). |
Alternatives
| Tool | Trade-off |
|---|---|
| esbuild | Mature, Go-based, similar role. oxc-transform is the Rust counterpart and aims to be faster + more correct on edge cases. esbuild wins on stability today. |
| swc | Rust transformer, the established choice. Larger surface, more mature, slightly slower than oxc. Used by Next.js, Vercel, Parcel. |
| @babel/core | The classic, slow but most-extensible transformer. Use when you need exotic plugins. |
| tsc | TypeScript's own compiler. Type-checks; slow; mostly used for .d.ts emit. |
| sucrase | JS-implemented transformer; fast for simple TS strip. Now in maintenance. |
Real-world recipes
The current API is intentionally small. Recipes here cover the common shapes; verify against current docs before adopting.
Transform a single TS string
import { transform } from "oxc-transform";
const source = `
const greet = (name: string): string => \`hello, \${name}\`;
export default greet("world");
`;
const result = transform("input.ts", source);
console.log(result.code);
Output:
const greet = (name) => `hello, ${name}`;
export default greet("world");
//# sourceMappingURL=...
The first argument is a filename hint — used for source maps and to infer JSX vs TSX. Replace .ts with .tsx to enable JSX parsing.
Transform JSX/TSX
import { transform } from "oxc-transform";
const source = `
function Hello({ name }: { name: string }) {
return <h1>Hello, {name}</h1>;
}
`;
const result = transform("Hello.tsx", source, {
jsx: {
runtime: "automatic", // new JSX transform — react/jsx-runtime
importSource: "react",
},
});
console.log(result.code);
Output:
import { jsx as _jsx } from "react/jsx-runtime";
function Hello({ name }) {
return _jsx("h1", { children: ["Hello, ", name] });
}
JSX-runtime options match React's modern JSX transform. Use runtime: "classic" for the older React.createElement form (rare in new projects).
Strip-types-only mode
For environments that just want types removed (no JSX, no down-leveling):
import { transform } from "oxc-transform";
const result = transform("file.ts", source, {
typescript: {
onlyRemoveTypeImports: false,
},
});
Useful for Node 22+ tooling that piggy-backs on the runtime's native TS stripping but wants a programmatic API.
Sourcemap
const result = transform("input.ts", source, {
sourcemap: true,
});
console.log(result.code);
console.log(result.map); // JSON sourcemap v3 string
Output:
... compiled code ...
{"version":3,"sources":["input.ts"],...}
The sourcemap format is standard v3. Pipe through source-map-cli or upload to your error tracker.
Use inside a build script
import { transform } from "oxc-transform";
import { readFile, writeFile } from "node:fs/promises";
const code = await readFile("src/index.ts", "utf8");
const out = transform("src/index.ts", code, {
sourcemap: true,
jsx: { runtime: "automatic" },
});
await writeFile("dist/index.js", out.code);
await writeFile("dist/index.js.map", out.map);
node build.mjs
Output:
(transformed src/index.ts → dist/index.js in ~3ms)
Pair with your own resolver/bundler if you need to compose multiple files. For full bundling, use rolldown (which embeds oxc) or esbuild.
As a Node loader (experimental)
There's no first-party oxc-loader for Node yet, but you can build one:
// register.mjs
import { register } from "node:module";
register("./oxc-loader.mjs", import.meta.url);
// oxc-loader.mjs
import { transform } from "oxc-transform";
import { readFile } from "node:fs/promises";
export async function load(url, context, nextLoad) {
if (!/\.(ts|tsx)$/.test(url)) return nextLoad(url, context);
const source = await readFile(new URL(url), "utf8");
const result = transform(new URL(url).pathname, source);
return { format: "module", source: result.code, shortCircuit: true };
}
node --import ./register.mjs ./src/server.ts
Output:
Server listening on :3000
This pattern is what tsx does internally with esbuild — swapping in oxc is a one-file experiment.
Production deployment
Production use of oxc-transform is mostly indirect — your bundler embeds it, you don't call it. Direct production use scenarios:
- Build-time TS stripping in custom toolchains. A monorepo with bespoke build steps can drop esbuild in favour of oxc-transform for marginal speed gains.
- Code generators / editors / language servers. Anywhere you'd reach for
@babel/core, oxc-transform is a faster alternative. - Sandboxed transformation services. A SaaS that compiles user-submitted TS to JS — oxc-transform's speed and memory profile are attractive.
Watch the version churn — pre-1.0 means breaking changes between minors. Always test against your fixtures before bumping.
Performance tuning
oxc-transform is fast by default; tuning is minimal.
Skip sourcemap for batch transforms
transform("input.ts", source, { sourcemap: false });
Sourcemap generation is the dominant cost for tiny inputs. Disable if you don't need them.
Reuse the transformer
Each call to transform() is independent. There's no context object today (unlike esbuild's incremental API). For repeated invocations, the cost is per-call — for batch jobs, parallelise across worker threads.
Avoid string round-trips
If you're chaining transformers (oxc → custom plugin → minifier), each step parses + serialises. Compose at the AST level via oxc-parser to skip serialisation.
Parallel with worker threads
import { Worker } from "node:worker_threads";
// dispatch many files across workers, each running oxc-transform
Native parallelism within oxc is being designed; until then, multi-worker is the way to scale beyond one core.
Version migration guide
Below 1.0, expect each minor to bring breakage. Migration patterns observed historically:
- API shape:
transform(filename, source, options)has been stable for several minors; older releases used a single-object signature. jsxoptions: the option shape moved from top-level keys (jsxRuntime: "automatic") into a nestedjsx: { ... }object.- Return value: older releases used
{ source, map }; current is{ code, map }. Verify on the version you install.
For any specific version, the authoritative migration source is the CHANGELOG in github.com/oxc-project/oxc.
A 1.0 freeze is on the roadmap; until then, pin and test.
Security considerations
- Pre-1.0 supply chain. Frequent releases mean less external security review. Pin tightly.
- Native binary install. Same model as esbuild and rolldown — platform-specific binaries via optional deps. Lockfile pins the binary version; for offline builds, stage in advance.
- No type checking. oxc-transform strips types but doesn't enforce them — same as esbuild / tsx. Type-driven security boundaries need explicit runtime validation.
- Source-map paths. Default sourcemap output includes the filename you passed; if that's a real disk path, it leaks into the map. Pass a virtual path for libraries published as artefacts.
- AST output (oxc-parser). If you use
oxc-parserdirectly, the AST is in a shape inspired by ESTree but with oxc-specific fields. Code that walks it assumes that schema — verify cross-version.
Testing & CI integration
# .github/workflows/ci.yml
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
- run: npm ci --include=optional
- run: npx tsc --noEmit # type-check
- run: node ./scripts/build.mjs # invokes oxc-transform
- run: node dist/index.js # smoke test
For tooling that embeds oxc-transform, snapshot-test the transformed output across a corpus — pre-1.0 means real output diffs across versions.
Ecosystem integrations
- rolldown uses
oxc-parserinternally for parsing during bundling. Going forward, more of the oxc toolchain (resolver, transformer) is being threaded in. - Vite indirectly via rolldown — Vite is the consumer that brings oxc to most developers without their having to think about it.
- oxlint — the linter half of oxc. Already used in some Next.js / Vercel projects as a faster ESLint replacement.
- rspack — community-maintained oxc plugins exist; not the default transformer there yet.
- tsdown — a thin tsup-compatible CLI built on oxc-transform; published under
tsdownon npm.
Troubleshooting common errors
Cannot find module 'oxc-transform' after install
The platform binary optional dep didn't install. Fix:
npm install --include=optional
npm rebuild oxc-transform
Output:
added 3 packages, and audited 87 packages in 1s
SyntaxError on valid TS
oxc's parser is still maturing — rare syntax (deeply nested decorators, very old TS features) may parse differently than tsc. File a repro at the oxc issue tracker. Workaround: fall back to esbuild for that file.
Output bytes differ from esbuild
Expected — different implementations. Verify behaviour with smoke tests; raw bytes will differ.
decorators option ignored
Decorator support is in progress; some target/runtime combinations don't yet emit the same metadata as tsc with emitDecoratorMetadata: true. If you need metadata for NestJS / TypeORM, stay on tsc or swc until oxc covers it fully.
Performance regression in newer version
Possible during pre-1.0 — micro-benchmarks shift between releases as the team focuses on correctness vs speed. Run your own benchmark against your codebase, not the oxc README numbers.
When NOT to use this
- Production-critical builds today. Pre-1.0 churn means version pinning + tests on every bump. esbuild / swc are stabler choices.
- Decorator-metadata-heavy stacks (NestJS, TypeORM). Metadata emission isn't on full parity yet. Stay on
tscuntil oxc closes the gap. - Edge-case TS syntax. The parser is excellent but newer; rare edge cases may misparse. Fall back to esbuild / tsc for unusual syntax.
- Indirect consumption. Most developers should let Vite + rolldown adopt oxc on their behalf; direct consumption is only worth it for tooling authors.
- Type-checking pipelines. oxc-transform doesn't type-check. For type safety, pair with
tsc --noEmitregardless of which transformer you use.
See also
- Packages: npm-esbuild — the Go-based alternative
- Packages: npm-rolldown — the bundler that uses oxc internally
- JavaScript: typescript — language features transformed
- Concept: HTTP — delivered output context