
21 October 2026 · 9 min
TypeScript in Rust: benchmark before you migrate
Cloudflare and VoidZero introduced the experimental tsrs TypeScript checker on 20 October. Here is how to test speed, memory and compatibility beside your current compiler without turning CI into an experiment.




A fast benchmark is not yet a migration plan
On 20 October 2026, Cloudflare and VoidZero, working with Owner.com, introduced tsrs: a Rust port of the TypeScript 7 type checker incubated in the Oxc project. The early numbers are eye-catching. Cloudflare reports up to eight times faster checking and roughly 70 per cent less memory than TypeScript 7.0 when both use the same number of type-check workers.
The wrong response is to replace tsc with tsrs in every pipeline the next morning. The useful response is a controlled parallel test. A type checker saves time only when it evaluates the same code reliably, catches the same relevant mistakes and fits the editor, CI and build workflow around it.
This article lays out how we would evaluate a new checker: a reproducible baseline, separate performance dimensions, a diagnostics comparison and a rollback that does not require heroics.
What was actually announced
tsrs is not a new TypeScript dialect. Cloudflare explicitly says it is not trying to fork the language or take its design in another direction. The project aims to port TypeScript 7 faithfully to Rust. The TypeScript team should remain in control of language semantics, while suitable improvements can also be contributed back to the official Go implementation.
The checker is experimental today. Its repository names a stable release against TypeScript 7.1 with 100 per cent conformance as the goal, but it also documents current differences and missing features. --init and --showConfig are not supported yet, for example, and diagnostic ordering may differ.
That distinction matters. “Drop-in replacement” describes the intended interface and destination. It does not guarantee that every tool, plugin and internal compiler API behaves identically today.
Put the benchmark number in context
“Up to 8× faster” is a measurement, not a law of nature. Cloudflare compares tsrs with TypeScript 7.0 using the same number of check workers. The same post also shows TypeScript 7.1 beta running up to 2.5 times faster than 7.0. In addition, tsrs ships with an adaptive default configuration that may use more memory on a given machine to gain more speed.
Three rules follow for a product team:
- compare identical versions, worker counts and compiler options;
- measure cold and warm runs separately;
- evaluate elapsed time, peak memory and result quality together.
A fast result on a large CI machine says little about a developer laptop, a constrained container or a warm monorepo. We do not copy someone else's result into a business case. We copy the method and run it on our own workloads.
Build an honest baseline first
Measure the existing process before adding the new tool. Otherwise the comparison is against memory rather than evidence.
A useful baseline records, for every representative project:
- exact commit and clean checkout;
- Node, TypeScript and package-manager versions;
- unchanged tsconfig files and lockfiles;
- machine profile or CI runner class;
- five cold and ten warm runs;
- wall-clock time, CPU time and peak memory;
- exit code and complete diagnostics;
- separate values for local development and CI.
Do not pick only the biggest repository. A UI app, an API service, a shared library and a project using Project References expose different workloads. If a tool shines only in a synthetic giant but barely changes the normal feedback loop, its product value is smaller than the headline.
Run beside the current checker, not instead of it
The first trial stays outside the critical path. The existing TypeScript check remains authoritative; tsrs runs beside it and reports as a non-blocking job.
The current project README suggests:
pnpm add -D tsrs
pnpm exec tsrs --noEmit
Pin the exact package version in the lockfile and store measurements as CI artefacts. A comparison script may normalise paths and timing noise, but it must not rewrite the substance of diagnostics.
This shadow mode answers four questions without production risk:
- Does the checker handle every relevant tsconfig shape?
- Does it find the same errors as the established check?
- How stable are time and memory across repeated runs?
- Which integrations call TypeScript APIs directly and bypass the CLI?
Only after those answers remain stable for several days should the new job become optionally blocking.
Compare meaning, not just exit codes
Exit codes are too coarse. Two checkers may both return 1 while finding different problems. Conversely, the same diagnostics may appear in a different order — a difference already documented by tsrs.
We compare structured fields instead:
- diagnostic code;
- file and position;
- severity;
- core message after removing unstable paths;
- number and type of missing or additional diagnostics.
Every difference enters a small compatibility list with one of three states: explained, accepted or blocker. Different ordering is usually explained. A missing unsafe-type error is a blocker. A correct additional diagnostic may be accepted, but it could require a planned cleanup.
The goal is not a byte-for-byte identical text file. It is demonstrably equivalent protection for the code the team actually ships.
Memory is a product feature of developer tooling
Lower memory use is not merely an infrastructure metric. It controls how many CI jobs can run in parallel, whether an agent can complete its checks inside a sandbox and whether a developer can keep the editor, browser and containers responsive at the same time.
Measure peak RSS rather than only an average. Important cases include:
- a full monorepo check;
- an incremental run after a small change;
- several packages checked concurrently;
- repeated runs on the same CI class;
- a smaller runner with a realistic memory limit.
If a faster checker wins only by using many more workers, include their memory and CI cost in the result. Cloudflare itself notes that the adaptive default can trade extra memory for more speed. That is exactly why the benchmark needs fixed parameters.
Editor and CI are separate migrations
A faster command-line check does not automatically make the editor faster. Completion, Go to Definition, Rename, project loading and plugins depend on the language server and often on APIs far beyond tsc --noEmit.
Treat three layers separately:
CI checker: The easiest to isolate because input and output are clear.
Local watch mode: Central to the feedback loop but more sensitive to incremental state.
Language server: Must be evaluated with the real editors, workspace sizes and plugins used by the team.
A team can adopt the CI checker first while keeping the editor unchanged. A single big-bang migration makes failures harder to attribute and turns a simple rollback into a larger event.
WebAssembly is an opportunity, not a requirement
Cloudflare cites Rust's WebAssembly fit as a reason for the port. The project already provides @tsrs/wasm for Node and browsers. That opens interesting possibilities: type checking inside browser IDEs, isolated build environments and fully sandboxed agent workflows.
For an ordinary product pipeline, it is not yet a migration reason by itself. A browser demo does not answer every question about file systems, Project References, package resolution or editor plugins.
Treat WASM as a separate product experiment:
- What exactly should run client-side?
- Which files may reach the browser?
- What are download and initialisation costs?
- Which APIs differ from a native process?
- How will the same TypeScript version be reproduced on the server?
Only a specific user or platform benefit justifies the additional runtime.
A migration gate needs explicit criteria
“It feels faster” is not a release criterion. Before the new checker can block merging, define a scorecard:
- Conformance: no unexplained missing diagnostics in reference projects;
- Compatibility: required CLI options and project modes work;
- Performance: median runtime improves materially on the team's runners;
- Stability: no intermittent crashes or non-reproducible results;
- Operations: version is pinned, caching understood and rollback documented;
- Tooling: named owners exist for editor, CI and plugin questions.
It is acceptable for a criterion to remain open. The deployment simply stays narrower — perhaps as a fast additional check rather than the only merge gate.
Three phases instead of one switch
Phase 1 — Observe: tsrs runs non-blocking on selected projects. The team collects time, memory and diagnostic diffs.
Phase 2 — Limit: The new checker becomes blocking for compatible projects, while the official checker remains as a fallback and reports differences. A simple CI variable switches back.
Phase 3 — Simplify: Only after several stable releases does the team remove the duplicate run where conformance and integrations are proven. Exceptional projects retain the old path until their blocker is resolved.
Test the rollback before Phase 2. One commit or pipeline variable should be enough. If recovery requires several teams and runner reinstallation, the migration is not operationally ready.
Common benchmark mistakes
The most misleading conclusions usually come from the experiment rather than the compiler:
- comparing a cold old run with a warm new one;
- using different worker counts or machine sizes;
- publishing only the fastest sample;
- mistaking a cache hit for checker performance;
- counting diagnostics without matching them;
- inferring editor performance from a CLI test;
- adding an unpinned experimental package to the main pipeline;
- switching a whole monorepo after one successful demo.
A good benchmark is boring: fixed inputs, repeated runs, complete results and documented exceptions. That boredom is what makes the decision credible.
What we would do today
tsrs is an exciting signal. TypeScript tooling is becoming faster, more portable and better suited to isolated development environments. It is also explicitly an experimental port with a clearly stated conformance target.
Our practical next step would be a one-week shadow test across two to four representative repositories. We would leave the official TypeScript pipeline unchanged, collect performance and diagnostic diffs, and make a decision from the scorecard after the week.
If the checker wins, the result is more than a faster pipeline: it is a proven migration path. If it does not win yet, the team still gains something valuable — a clean baseline for evaluating TypeScript 7.1 and future versions honestly.
Sources



