ternTS · written in Tern · experimental

TypeScript, exactly like tsc. 6× faster than swc.

ternTS turns TypeScript into the JavaScript tsc would write, including the legacy decorators and emitDecoratorMetadata that NestJS, TypeORM and Angular run on. Same output on 37,000 real files; a fraction of the time.

32 msall 1,959 NestJS files, one threadswc 202 ms · tsc 1.44 s
108 msNestJS save to restarted appnest start --watch 676 ms
37,319files checked against tsc, all identicalNestJS, VS Code, Grafana, Excalidraw, Immich, Twenty
1.33 sall of VS Code: 13,454 files, 177 MBswc 6.07 s · tsc 40.2 s

Playground

Type TypeScript, get tsc’s JavaScript.

This is ternTS itself, compiled to WebAssembly and running in this page. Turn on Compare with tsc to run TypeScript 5.9’s transpileModule beside it and check the two outputs parse to the same program.

TypeScript
loading ternts.wasm…

      

Your code

Run it on a whole project.

Pick a folder, drop one here, or load a public GitHub repository. ternTS transpiles every .ts and .tsx file (skipping node_modules, dist and .d.ts), then tsc does the same so you can compare. Nothing is uploaded: it all runs in your browser.

A public GitHub repository
No project handy? 475 files, loads instantly

In the browser ternTS runs as single-threaded WebAssembly. The native ternts build uses every core and skips unchanged files, so it’s faster still. Options here are ternTS’ defaults (legacy decorators with metadata, ES2022+ output); ternts build reads them from your tsconfig.json.

Benchmarks

Faster than the Rust and Go rewrites.

Apple M4 Pro, Node 24, the latest release of each tool: swc 1.16.12, TypeScript 5.9.3, tsgo 7.0.2. node bench/run.mjs in the ternTS repository reproduces every number. Shorter bars are better.

Transpile NestJS in-process1,959 files, 4.8 MB, one thread; ms
ternTS32
swc202
tsgo624
tsc 5.91,440
Transpile VS Code in-process13,454 files, 177 MB, one thread; seconds
ternTS1.33
swc6.07
tsgo22.2
tsc 5.940.2
NestJS dev mode: save to new code answeringcats sample, median of 20 edits; ms
ternts dev --warm108
ternts dev298
nest (tsc)661
nest -b swc676
Whole build from the command lineNest packages, 971 files, all cores, ES modules; ms
ternts build66
tsgo --noCheck110
swc CLI185
tsc --noCheck1,000
Jest transform, steady stateNestJS repo, one worker, source maps; ms
ternts/jest267
@swc/jest392
ts-jest2,390
NestJS dev mode: cold startcats sample; ms
ternts dev288
ternts dev --warm333
nest -b swc1,367
nest (tsc)1,620

Correct

tsc’s output, checked three ways.

1. The same program as tsc. Every file goes through ternTS and through TypeScript 5.9’s transpileModule with the same options, and both outputs are parsed and compared, ignoring only formatting and the numbering of temp names like _a. That’s the check the playground above runs.

2. Nest’s own test suite. All 3,631 of Nest’s unit tests pass with ternTS as the TypeScript transformer.

3. Real apps, same behavior. Nine NestJS sample apps built with tsc and with ternTS answer the same requests byte for byte, including the Swagger document and GraphQL schema that Nest builds from decorator metadata.

CorpusFilesIdentical
NestJS repository1,9591,959
VS Code13,45413,432*
Grafana + Excalidraw (4,948 .tsx)10,18110,181
Immich server668668
Twenty server11,05711,057

* The 22 VS Code files that differ aren’t valid TypeScript on purpose (lint-error fixtures, a file cut off at 8 MB). tsc emits something for them anyway; ternTS reports the syntax error. Every corpus is identical in CommonJS, ES modules, with esModuleInterop + strictNullChecks, and with useDefineForClassFields; the .tsx files in all four JSX modes.

Experimental

Install

An early, experimental release: expect rough edges, and please tell us what breaks. The npm package carries a native binary for macOS and Linux (arm64 and x64) and WebAssembly for everything else, so you never install Tern.

npm i -D @ternlang/ternts@experimental
npx ternts build                # the project in ./tsconfig.json: files, outDir, module, decorators, jsx…
npx ternts dev --warm           # build, run, and restart on every save (replaces nest start --watch)

Jest

// jest.config.js
transform: {
  '^.+\\.(t|j|mj)sx?$': ['@ternlang/ternts/jest', { tsconfig: 'tsconfig.json' }],
}

Vite and Vitest

// vite.config.ts
import ternts from '@ternlang/ternts/vite';
export default defineConfig({ plugins: [ternts()] });

Node

# run TypeScript directly (Node 22.15+)
node --import @ternlang/ternts/register src/main.ts

Not done yet

Written in Tern

About 10,000 lines of Tern.

ternTS is written in Tern, a compiled language built for AI agents to write, that compiles to native code faster than Rust and Go. There’s no AST: the parser walks tokens and copies your source through, editing only what TypeScript adds.

Meet Tern →
1 MBthe whole transpiler as WebAssembly: what this page runs
No postinstalla prebuilt binary per platform, WebAssembly for the rest; nothing to compile