FILED 21 Oct 2026 6 MIN READ EN

Cloudflare Ported TypeScript to Rust for Wasm, Not for Speed

When Microsoft rewrote the TypeScript compiler from JavaScript to Go, the performance argument mostly closed. tsc got roughly 10x faster and far leaner.

On October 20, 2026, Cloudflare and VoidZero announced tsrs, a Rust port built with Max Schwenk of Owner.com and incubated inside the Oxc toolchain. It benchmarks up to 8x faster than TypeScript 7.0 while using about 70% less memory.

Sit with those numbers and you can still miss the point.

The port exists because a Rust compiler compiles to WebAssembly without dragging a garbage collector behind it. That property decides where your typechecker is allowed to live.

I maintain TypeScript monorepos and run agent fleets that typecheck in a loop. Read this as an infrastructure change rather than a language war.

The benchmark is real, and Cloudflare printed its own caveats

Both figures come with a control attached. The worker count matches, and the configuration was agreed with the TypeScript team.

That second half is worth more than the headline.

Compiler-port benchmarking has been a mess of numbers from bigger machines with looser flags. Cloudflare names that pattern first. What I carry into my evaluation:

  • the 8x is a ceiling across a benchmark suite, not a constant on your repository,
  • tsrs ships an adaptive configuration by default that spends more memory to run faster than the pinned config,
  • TypeScript 7.1 beta is already up to 2.5x faster than 7.0, with part of that coming back from tsrs work.

So the honest comparison for a team on TS 7.0 is tsrs against 7.1. Nobody is comparing against nothing.

A Go binary carries its collector into Wasm

Compile a Go program to WebAssembly and Go's garbage collector comes along for the ride. No build flag shaves it off.

The collector ships inside the module and manages memory the host cannot inspect.

Rust does not have that problem. A guest module with direct, predictable memory access costs less to run. That is the efficiency Cloudflare is selling.

The module gets smaller and the footprint drops. No collector spins inside your Worker.

HN commenter jerf put the size half more directly: shipping Go to Wasm "results in very large WASM packages for small amounts of code". A compiler is hardly small code, so that multiplier is large.

The deployment target is the argument

Workers have run Wasm for years. Native Rust support arrived a few weeks before this announcement, through a new Emscripten target for wasm-bindgen.

Stack them and a development toolchain runs end to end inside a sandbox, with nothing shelled out to a container.

Places that opens up, ordered by how soon I would use them:

  • a complete typecheck inside a Worker, for per-PR preview builds,
  • the same toolchain in a browser tab, so a contributor with no local setup still sees real diagnostics,
  • the compiler on an embedded device, where a Go runtime plus collector is too heavy to consider.

The browser case matters most for agent runners. If the compiler fits in a tab, it fits inside whatever isolation boundary the agent already has. That removes a shared volume from the design, plus a category of cross-tenant surprises.

A morning agent and a nightly matrix keep this alive

Cloudflare is explicit that tsrs is not a fork. The TypeScript team keeps control of language design, and the port follows it.

The maintenance section is where I stopped skimming. The model is copied from Vinext, their Next.js reimplementation. Each morning an agent reviews upstream changes and opens tracking issues for anything that could affect the port. Every night the compatibility matrix is regenerated by running the Next.js test suite against Vinext.

When something breaks, agents locate the change across both codebases. They build a reproduction, port the relevant tests, and propose a fix. Cloudflare says the same process now runs for TypeScript.

For a downstream port, that changes the failure mode. These projects rot because parity with thousands of upstream tests is human work nobody funds. Turn it into a nightly job with agents drafting the fixes, and it becomes a cost line instead of a burnout line.

Cloudflare also admits the field is crowded. Frontier models can now do large ports in days, so slopforks (a fast low-rigor AI clone) and fully re-architected ports keep appearing. Two things separate tsrs from that pile:

  • it follows the TypeScript team's design decisions,
  • and its performance findings go back upstream.

Without both, it is one more fast fork.

Two details show the team knows the sharp edges. Theo Browne is merging tsc-rs and tsrs into one package covering every TypeScript feature, LSP and content mappers included. Known divergences stay small, like the order diagnostics print in.

Where upstream is the real test

The relationship with Microsoft is friendlier than the usual fork war. Dan Rosenwasser of the TypeScript team turned up in the Hacker News thread (383 points, 184 comments) to say the quiet part: "a lot of the speed does not just come down to language choice".

He confirmed that some of what makes TS 7.1 faster and leaner came from optimizations discovered during the Rust port.

The concrete case is PR #64476 from maschwenk, which stopped the checker from building intersection properties that cannot reduce to never. The numbers in the PR body are the interesting bit.

On the mui-docs benchmark with four checkers, heap fell 41.8% and check time fell 38.9%. That came from roughly 80 lines of real change.

That PR was closed without being merged, which matters more than any benchmark here. Findings travel upstream faster than patches do. Assume the discovery lands in TypeScript eventually, and do not assume the diff will.

What I would change on Monday

Inner-loop economics are not CI economics. Fifteen seconds of typecheck in a pipeline is nothing.

An agent running an edit, typecheck, test loop dozens of times on one task pays that cost dozens of times. It pays while holding a container open.

npm install tsrs
npx tsrs

Memory is the wall I hit first. Each parallel checker owns its heap. On a box running four agent containers, 70% less RSS per checker decides whether a fifth fits.

Four moves I would make now:

  • track peak RSS per typecheck alongside wall time, because that is where the memory win shows up,
  • keep tsrs as a reporting job next to the real gate while it is experimental,
  • leave diagnostic ordering to the Go tsc until the divergences close,
  • put the loop inside the agent's own sandbox rather than on a shared build volume.

Two implementations, one language, and neither of them a fork. Go gave TypeScript its speed back in the CLI. Rust is giving it a second place to live, which is the win that matters once the compiler has to run somewhere far smaller than a VM.