Six small, fast tools that each replace one you use today: ts-r-dev, ts-r-build, ts-r-check, ts-r-lint, ts-r-run and ts-r-lsp. Each one reads the config you already have and works on its own, so you can switch one at a time.
Save to page updated, p50Shorter is faster. Measured on a real app.
ts-r-dev7.7 ms
Vite 8.3.477.5 ms
10×faster hot reload
Measured on a real app, against the tools you use today
Early numbers from pre-release builds on our reference app, a real TypeScript monorepo of 1,983 modules. Every number says how it was measured: open “How we measured” on any tile.
Headless Chrome drives both servers: 5 cold and 5 warm starts (median), then 50 measured edits of sign-in-form.tsx after 3 warm-ups, timed in the browser. RSS is the whole server process group.
Machine
Apple M-series Mac, macOS arm64, release build (the exact chip was not recorded)
Software
ts-r-dev release build; Vite 8.3.4 with @vitejs/plugin-react 6.1.2; both servers capped at 4 threads
Input
A scratch copy of private-app's apps/web with its dependencies installed
ts-r-buildMeasuredreplaces esbuild, Rollup, Vite build
4.8×faster rebuilds
ts-r-build269 ms
esbuild 0.28.2 (context.rebuild)1,294 ms
First build plus 20 edit-and-rebuild cycles
How we measured
Measured
Wall time of whole processes, median of 10 runs for the smoke entry; cargo xtask bench for build-cold and build-incremental (ts-r's examples/build_loop.rs --edit against bench/js/esbuild-rebuild.mjs)
Machine
Apple M-series Mac, macOS arm64, release build (the exact chip was not recorded)
Software
ts-r-build release build with 4 threads; esbuild 0.28.2 pinned in bench/package.json
Input
private-app apps/web smoke-entry.tsx, which server-renders the shared layout components; the incremental run edits src/components/footer.tsx
Apple M-series Mac, macOS arm64, release build (the exact chip was not recorded)
Software
Node 24.21.0; tsx 4.23 run as its binary (npx tsx adds about 400 ms); ts-r-run with 4 compile threads and source maps on
Input
A generated project of 1,000 TypeScript modules (interfaces, classes, typed functions, .ts imports so Node type stripping can run it too), and hello.ts
ts-r-lspMeasuredreplaces tsserver and the ESLint server
12×faster first errors
ts-r-lsp18 ms
tsserver 6.0.3218 ms
First diagnostics, largest file (168 KB)
How we measured
Measured
A scripted LSP client: first diagnostics, hover, definition and completion latency, keystroke to diagnostics (100 keys, 150 ms apart) on one file, and memory with one file or all 649 open (24 projects, 15 s settle)
Machine
Apple M-series Mac, macOS arm64, release build (the exact chip was not recorded)
Software
ts-r-lsp release build with the ts-r backend and the tsc parity check off; tsserver 6.0.3 (the project's TypeScript); TypeScript 7.0.2's native LSP (tsc --lsp)
Input
private-app; the largest file is packages/api-client/src/schema.gen.ts, the TSX file apps/web/.../card-form.tsx
Command
scripts/limit.sh -- node editors/vscode/bench/editor-latency.js ts-r target/release/ts-r-lsp <root> <file> (tsserver and tsgo modes for the others)
Recorded in
commit 59268bf
What we haven’t measured yet
ts-r-build against Rolldown and Vite's production build.
ts-r-check against ts-rust, and on the 60-repository corpus the plan describes.
ts-r-lint against Biome, and any type-aware lint rules (ts-r-lint has none yet).
ts-r-dev against Vite 8 on the generated 1,000 to 50,000-module apps.
Linux and Windows runs, and runs on a dedicated benchmark machine.
Not ready yet. Nothing is on npm yet. The type checker doesn’t give the same errors as tsc on every project, so keep tsc in CI until it does.
One engine under six tools
Every tool parses with the same front end, resolves modules the same way and shares one cache, so work done by one is reused by the next. Nothing underneath is borrowed: no swc, no oxc, no esbuild, no TypeScript. Pick a tool to see what it’s built on.
ts-r-dev transforms only the file you saved and pushes that one update to the browser, so a save costs about the same at 50,000 modules as at 1,000. The plan’s target is under 30 ms.
Save to browser updated, p50, as the app growsLower is faster, in ms. Generated apps from 1,000 to 50,000 modules.
010203040
Target: under 30 ms
4.9 ms at 1,000 modules
4.8–5.0 ms at 10,000 modules
5.4 ms at 50,000 modules
1,00010,00050,000
Checked against the tools it replaces
Speed only counts if the answers are right. Each part runs the reference tool’s own tests, or compares output on real code, and the gaps are published with the wins.
Module resolution100%
63,958 of 63,958 resolutions match (0 differences)
Every resolution in tsc --traceResolution for 24 tsconfig files of private-app. Commit 856e43d.
tsconfig loading100%
49 of 49 configs match tsc --showConfig exactly
private-app tsconfig files. Commit 856e43d.
JavaScript output (emit)100%
339 of 339 files match
private-app apps and packages, 15 tsconfig files. Commit e92e486.
JavaScript output (emit)91.0%
1,611 match, 159 differ
tsc 7's own emit baselines (tests below ES2022, outFile, AMD/System/UMD and files with syntax errors skipped). Commit b46cb28.
Parse, print, parse again100%
18,079 match, 0 differ
TypeScript's tests/cases (1,133 files with syntax errors skipped). Commit f3c5476.
Binder diagnostics90.0%
398 of 442 tests match exactly; 1,683 of 1,789 expected diagnostics found
tsc 7.0.2 baselines for the binder's error codes. Commit 16a6b7e.
Type checker58.0%
58.0% of 13,398 conformance test variants exact; 937 variants with a diagnostic tsc does not report
Every case of the published ESLint and typescript-eslint tests for the 103 rules. Commit 27c280e.
Packages passing each stageLonger is better
Parse every file99.9%
Bundle and run (vs esbuild)92.2%
Transform TypeScript (vs tsc)87.5%
Check an import of it (vs tsc 7)77.6%
Own test suite0%
The top 1,000 npm packages, each stage compared with tsc 7 or esbuild. No package’s own test suite passes with ts-r swapped in yet.
How it’s built
Written from scratch
The lexer, parser, binder, checker, bundler, minifier, linter, dev server and language server are all written in this repo, in Rust, with no other compiler underneath.
Other tools are the oracle
TypeScript’s conformance tests, esbuild’s bundler tests and ESLint’s rule tests run against ts-r. Where ts-r disagrees, ts-r is wrong until shown otherwise.
Every number has a commit
Each benchmark records its machine, input, command and the commit that measured it. Numbers that miss their targets are published too.
One tool at a time
Each tool is its own binary that reads your existing config. Adopt the linter this week and keep tsc, Vite and ESLint for everything else.
The repo’s own checks
# TypeScript’s tests, libs and diagnostics, pinned$ cargo xtask upstream sync
# tsc 7 as the reference for every diagnostic$ cargo xtask oracle
# against tsc 7, esbuild, oxc and tsx; 5% regression gate$ cargo xtask bench
# the top 1,000 npm packages, stage by stage$ cargo xtask ecosystem
Numbers on this site were last updated on 15 October 2026.
Frequently asked questions
What is ts-r?
Six command-line tools for TypeScript, written from scratch in Rust: a dev server, a bundler, a type checker, a linter, a runner and a language server. Each one replaces one tool you use today.
Do I have to switch everything at once?
No. Each tool works on its own next to tsc, ESLint and Vite, and reads the config you already have: tsconfig.json, your ESLint config, your vite.config. Switch one at a time, in any order.
Is it a fork of tsc, esbuild or oxc?
No. Every layer (lexer, parser, type checker, bundler, minifier, linter) is written in this project. Other tools’ test suites and outputs are used to check that ts-r gives the same answers.
Will it be free?
Yes. ts-r will be open source under MIT OR Apache-2.0, with no paid tier. Sponsorships help fund development time.
When can I use it?
It runs from source today and isn’t on npm yet. The type checker doesn’t give the same errors as tsc on every project yet, so keep tsc in CI until it does.