Every number here was measured by the ts-r project and recorded in a commit message, a crate's AGENTS.md or a design record. Each section says what was measured, on what machine and project, how many runs, the command that reproduces it and the commit that recorded it. Pre-alpha: only the pieces that exist today are measured, and the numbers that miss their targets are shown too. Lower is better unless a chart says otherwise.
ts-r-dev against Vite 8 on excalidraw
excalidraw (about 500 TypeScript modules served from source, 47 dependency entries) served by ts-r-dev and by Vite 8.3.4 with @vitejs/plugin-react 6.1.2. Start is process spawn until the canvas and welcome screen are in the page; cold means an empty ts-r cache and no Vite dependency cache. Both kept React state through all 53 edits with 0 full reloads. SCSS is replaced by an empty stylesheet for both servers (ts-r-dev does not compile it yet).
Start to first render, medianShorter is faster, in ms
ts-r
Other tools
ts-r-dev, warm538 ms
ts-r-dev, cold939 ms
Vite 8.3.4, warm1,032 ms
Vite 8.3.4, cold1,107 ms
Show as table
Start to first render, median (ms, lower is better)
Setup
Median
Notes
ts-r-dev, warm
538 ms
ts-r-dev, cold
939 ms
includes pre-bundling 47 dependency entries into 133 files
Vite 8.3.4, warm
1,032 ms
Vite 8.3.4, cold
1,107 ms
Save to page updated, p50Shorter is faster, in ms
ts-r
Other tools
target < 30 ms
ts-r-dev8.6 ms
Vite 8.3.435 ms
Show as table
Save to page updated, p50 (ms, lower is better)
Setup
p50
p95
ts-r-dev
8.6 ms
9.0 ms
Vite 8.3.4
35 ms
37.2 ms
Dev server memory after the editsShorter is faster, in MB
ts-r
Other tools
ts-r-dev153 MB
Vite 8.3.4364 MB
Show as table
Dev server memory after the edits (MB, lower is better)
Setup
RSS after 50 edits
After first load
Notes
ts-r-dev
153 MB
151 MB
includes the Node process that runs vite.config
Vite 8.3.4
364 MB
371 MB
How we measured
Measured
Headless Chrome (a fresh one per page load) drives both servers: 5 cold and 5 warm starts (median), then 50 measured edits of the welcome-screen heading after 3 warm-ups, timed in the browser. RSS is the whole server process group.
Machine
Apple M-series MacBook (macOS arm64, 16 cores, 48 GB), shared with other jobs while measuring; release build, 4 threads
Software
ts-r-dev release build; Vite 8.3.4 with @vitejs/plugin-react 6.1.2 pinned in bench/package.json; both servers capped at 4 threads
Input
excalidraw at the commit pinned in bench/repos.toml, with the harness in bench/dev/excalidraw (index.html, main.tsx rendering excalidraw-app/App, vite.config.mjs with its source aliases)
Time from saving a file to the browser having re-imported the changed module and run its callbacks, on generated apps. The plan's target is under 30 ms at p50, staying flat as the project grows. Vite has not been measured on these generated apps yet.
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
Show as table
Save to browser updated, p50 (ms, lower is better)
Setup
p50
p95
First save of a file
Initial page load
1,000 modules
4.9 ms
5.9–6.9 ms
7–17 ms
0.3 s
10,000 modules
4.8–5.0 ms
5.3–6.4 ms
7–17 ms
1.7 s
50,000 modules
5.4 ms
8.3 ms
16 ms
13.5 s
How we measured
Measured
Browser-side timing in headless Chrome: 47 measured edits per size after 3 warm-up edits. Ranges are across runs; the bar shows the upper end.
Machine
Apple M-series Mac, macOS arm64, release build (the exact chip was not recorded)
Software
ts-r-dev release build, headless Chrome
Input
Generated JavaScript apps of 1,000, 10,000 and 50,000 modules; one self-accepting module under a 100-wide import tree is edited. The first save of a file goes through FSEvents, later saves through the kqueue fast path.
Bundling two public projects: three.js x10 (ten copies of three.js, minified IIFE with source maps) and the excalidraw app (minified ESM). Only three.js x10 is drawn as bars: both bundlers produce the same exports from the same input. Without its persistent cache ts-r-build is slower than esbuild there. On excalidraw ts-r-build does less work than esbuild: it does not bundle template-literal import() yet, so it leaves out the 61 locale chunks esbuild emits (7.2 MB of output against 9.3 MB). Those runs, the single bundle and the 20 rebuilds, are in the table with that note, not drawn next to esbuild. Rolldown and Vite's production build have not been measured.
Bundle three.js x10, minifiedShorter is faster, in ms
ts-r
Other tools
esbuild 0.28.2225 ms
ts-r-build, persistent cache241 ms
ts-r-build, no cache378 ms
Show as table
Bundle three.js x10, minified (ms, lower is better)
Setup
Median of 10 runs
esbuild 0.28.2
225 ms
ts-r-build, persistent cache
241 ms
ts-r-build, no cache
378 ms
excalidraw (not like-for-like), memory, output and the oracle
What
ts-r-build
esbuild 0.28.2
Notes
Bundle excalidraw, minified: no cache / persistent cache
255 / 132 ms
201 ms
Median of 10 runs. Not like-for-like: ts-r-build leaves out the 61 locale chunks esbuild emits (7.2 MB of output against 9.3 MB)
excalidraw: first build plus 20 edit-and-rebuild cycles, one process
1,358 ms
3,457 ms (context.rebuild)
Median of 5 runs. Not like-for-like: every build leaves out the 61 locale chunks
Peak memory, excalidraw, no cache / cached
317 / 152 MB
624 MB
Without the 61 locale chunks
Peak memory, three.js x10, no cache / cached
459 / 275 MB
695 MB
three.js x10 output
7.88 MB (+2.2%), same exports
7.71 MB
esbuild's own bundler tests (oracle)
643 of 746 compared cases pass (86.2%)
reference
How we measured
Measured
Wall time of whole processes with hyperfine (cargo xtask bench --repos), median; peak RSS of one extra run (--memory). Rebuilds: examples/build_loop.rs --edit against bench/js/esbuild-rebuild.mjs, editing excalidraw-app/components/AppWelcomeScreen.tsx
Machine
Apple M-series MacBook (macOS arm64, 16 cores, 48 GB), shared with other jobs while measuring; release build, 4 threads
Software
ts-r-build release build with 4 threads; esbuild 0.28.2 pinned in bench/package.json
Input
excalidraw (bench/dev/excalidraw/main.tsx, .woff2 as files, .scss empty) and three.js x10 at the commits pinned in bench/repos.toml
tRPC's own ESLint config with every rule ts-r-lint does not implement removed, given to both tools as the same file, on the same 147 files: 48 rules, without type information on either side. Both report 0 problems from those rules. The bars are the run where ts-r-lint evaluates the config in Node every time, as ESLint does; most of its time is that Node process. By default ts-r-lint caches the evaluated config and then takes 15.5 ms, but ESLint has no such step to skip, so that run is in the table, not drawn next to ESLint. With type-aware rules the runs are not comparable yet: on tRPC ts-r-lint's parity gate turns those rules off (its type check reports one error tsc 7 does not), and with the gate off it reports 11 problems ESLint does not.
tRPC, same 48 rules, config evaluated each runShorter is faster, in ms
ts-r
Other tools
ts-r-lint, config not cached733 ms
ESLint 10.10.01,015 ms
Show as table
tRPC, same 48 rules, config evaluated each run (ms, lower is better)
Setup
Median of 5 runs
Notes
ts-r-lint, config not cached
733 ms
Node evaluates eslint.config.js on every run
ESLint 10.10.0
1,015 ms
Cached config, memory, and the type-aware rules
Run
Time
Peak memory
Notes
ts-r-lint, same 48 rules, config cached (its default)
15.5 ms
9 MB
Skips evaluating the config, which ESLint does on every run, so not drawn next to ESLint
ts-r-lint, same 48 rules, config not cached
733 ms
336 MB
Peak is the Node process that evaluates the config
ESLint, same 48 rules
1,015 ms
515 MB
0 problems from the rules, like ts-r-lint
ts-r-lint, same 80 rules with the 32 type-aware ones, parity gate off, empty cache
952 ms
335 MB
Not like-for-like: 11 problems ESLint does not report (unbound-method 4, no-unnecessary-type-assertion 4, switch-exhaustiveness-check 2, dot-notation 1). By default the parity gate turns these rules off on tRPC
ESLint, same 80 rules (typescript-eslint projectService)
2,605 ms
973 MB
0 problems from the rules
How we measured
Measured
Wall time of the whole command with hyperfine (cargo xtask bench --repos trpc lint-trpc-same-rules), median of 5 runs after 1 warm-up; peak RSS of the largest process in one extra run. Before each tool's runs, bench/js/eslint-same-rules.mjs writes the restricted configs from the binary's --list-rules. Untyped runs: ts-r-lint --no-type-check, ESLint with parserOptions project and projectService off. Problems compared once from each tool's JSON output by file, rule, line and column
Machine
Apple M-series MacBook (macOS arm64, 16 cores, 48 GB), shared with other jobs while measuring; release build, 4 threads
Software
ts-r-lint release build (crates as of a7210058) with 4 threads; ESLint 10.10.0 and typescript-eslint 8.70.0 from tRPC's lockfile; Node 24.21.0
Input
tRPC packages/server/src and packages/client/src (147 files) at the commit pinned in bench/repos.toml; tRPC's eslint.config.js limited to the 80 of its 126 configured rules ts-r-lint implements (48 without the type-aware ones)
Each project linted with its own config. Not like-for-like: ESLint also runs plugin rules ts-r-lint does not have (on TypeORM most of its problems come from jsdoc rules), and where ts-r-check's diagnostics differ from tsc's, ts-r-lint runs without type information (its parity gate), so its type-aware column is a type check plus the untyped rules. Because ESLint does more work, these runs are only in the table, with no bars and no totals. The rules themselves match ESLint's and typescript-eslint's test suites (see Correctness).
Each project with its own config, and memory (not like-for-like)
Run
Time
Peak memory
Notes
tRPC server and client sources: ts-r-lint / no type check
186 / 20 ms
148 / 9 MB
Median of 3 runs
tRPC: ESLint, type-aware
2,566 ms
992 MB
Also runs plugin rules ts-r-lint lacks, so not a like-for-like comparison
TypeORM packages/typeorm/src: ts-r-lint / no type check
810 / 194 ms
380 / 26 MB
Median of 3 runs
TypeORM: ESLint, type-aware
6,718 ms
1,748 MB
Most of its problems come from jsdoc rules ts-r-lint lacks, so not a like-for-like comparison
Playwright core sources: ts-r-lint / no type check
725 / 59 ms
465 / 17 MB
Playwright core sources: ESLint
5,441 ms
2,341 MB
Also runs plugin rules ts-r-lint lacks, so not a like-for-like comparison
date-fns pkgs/core/src: ts-r-lint
76 ms
14 MB
date-fns pkgs/core/src: oxlint (its own config)
348 ms
301 MB
Different rule set, so not a like-for-like comparison
How we measured
Measured
Wall time of the whole command with hyperfine (cargo xtask bench --repos), median of 3 to 5 runs; peak RSS of one extra run
Machine
Apple M-series MacBook (macOS arm64, 16 cores, 48 GB), shared with other jobs while measuring; release build, 4 threads
Software
ts-r-lint release build with 4 threads; each repo's own ESLint or oxlint from its lockfile
Input
tRPC, TypeORM, Playwright and date-fns at the commits pinned in bench/repos.toml, with their own lint configs
Type checking five public projects from the command line, cold (no saved history), against TypeScript 7.0.2's native tsc. These repos do not type-check cleanly under TypeScript 7, and ts-r-check does not report the same diagnostics as tsc on them yet: it reports extra ones on all five (27 on date-fns to 1,333 on RxJS in the last comparison) and misses some of tsc's. It also skips checks it does not implement yet, so these times will move as the checker grows.
Check all five projects, total wall timeShorter is faster, in ms
ts-r
Other tools
ts-r-check1,936 ms
tsc 7.0.23,044 ms
Show as table
Check all five projects, total wall time (ms, lower is better)
Setup
Sum of the medians
ts-r-check
1,936 ms
tsc 7.0.2
3,044 ms
Cold check, wall timeShorter is faster, in ms
tRPC packages/server108 ms
date-fns pkgs/core226 ms
RxJS packages/rxjs462 ms
TypeORM packages/typeorm548 ms
Playwright592 ms
Show as table
Cold check, wall time (ms, lower is better)
Setup
ts-r-check, median of 5
tsc 7.0.2
tRPC packages/server
108 ms
189 ms
date-fns pkgs/core
226 ms
323 ms
RxJS packages/rxjs
462 ms
1,280 ms
TypeORM packages/typeorm
548 ms
567 ms
Playwright
592 ms
685 ms
Cold check, peak memoryShorter is faster, in MB
tRPC packages/server117 MB
date-fns pkgs/core216 MB
RxJS packages/rxjs458 MB
TypeORM packages/typeorm377 MB
Playwright463 MB
Show as table
Cold check, peak memory (MB, lower is better)
Setup
ts-r-check, one run
tsc 7.0.2
tRPC packages/server
117 MB
294 MB
date-fns pkgs/core
216 MB
558 MB
RxJS packages/rxjs
458 MB
1,168 MB
TypeORM packages/typeorm
377 MB
826 MB
Playwright
463 MB
1,094 MB
Warm runs, and each repo's own TypeScript
Project
ts-r-check, saved history, nothing changed
The repo's own tsc
tRPC
23 ms
1,130 ms
date-fns
78 ms
324 ms
RxJS
57 ms
2,468 ms
TypeORM
126 ms
3,915 ms
Playwright
40 ms
4,754 ms
How we measured
Measured
Wall time with hyperfine (cargo xtask bench --repos), median of 5 runs; peak RSS of one extra run. Every tool checks the same wrapper tsconfig (noEmit, not incremental)
Machine
Apple M-series MacBook (macOS arm64, 16 cores, 48 GB), shared with other jobs while measuring; release build, 4 threads
Software
ts-r-check release build; TypeScript 7.0.2 (native tsc) pinned in bench/package.json; each repo's own TypeScript
Input
tRPC, date-fns, RxJS, TypeORM and Playwright at the commits pinned in bench/repos.toml
ts-r-lsp with our checker against tsserver and TypeScript 7's LSP
Under 500 MB on these projects; large ones not measured
A scripted LSP client on three public projects: date-fns (1,641 sources), RxJS (231) and tRPC (154). ts-r-lsp uses far less memory than tsserver and TypeScript 7's native LSP, with every source open too, but it is slower than TypeScript 7's LSP to first diagnostics on all three and per keystroke on two of them (it re-checks each edit on a fresh checker). It also reports a few diagnostics tsc does not on the opened RxJS and tRPC files. These are medium projects: the 500 MB target is for large ones, which have not been measured.
RxJS: memory with all 231 sources openShorter is faster, in MB
ts-r
Other tools
target ≤ 500 MB
ts-r-lsp377 MB
TypeScript 7 LSP (tsc --lsp)820 MB
tsserver (the repo's TypeScript)1,091 MB
Show as table
RxJS: memory with all 231 sources open (MB, lower is better)
Setup
RSS
ts-r-lsp
377 MB
TypeScript 7 LSP (tsc --lsp)
820 MB
tsserver (the repo's TypeScript)
1,091 MB
date-fns: memory with all 1,641 sources openShorter is faster, in MB
ts-r
Other tools
ts-r-lsp232 MB
TypeScript 7 LSP (tsc --lsp)710 MB
Show as table
date-fns: memory with all 1,641 sources open (MB, lower is better)
Setup
RSS
Notes
ts-r-lsp
232 MB
TypeScript 7 LSP (tsc --lsp)
710 MB
tsserver did not publish diagnostics within the harness's 120 s
tRPC router.ts: keystroke to diagnostics, p50Shorter is faster, in ms · TypeScript 7 is faster here
ts-r
Other tools
TypeScript 7 LSP6.2 ms
ts-r-lsp9.4 ms
tsserver24.3 ms
Show as table
tRPC router.ts: keystroke to diagnostics, p50 (ms, lower is better)
Setup
p50
p95
TypeScript 7 LSP
6.2 ms
7.4 ms
ts-r-lsp
9.4 ms
10.5 ms
tsserver
24.3 ms
29.3 ms
tRPC router.ts: first diagnosticsShorter is faster, in ms · TypeScript 7 is faster here
ts-r
Other tools
TypeScript 7 LSP58 ms
ts-r-lsp224 ms
tsserver800 ms
Show as table
tRPC router.ts: first diagnostics (ms, lower is better)
Setup
Time
TypeScript 7 LSP
58 ms
ts-r-lsp
224 ms
tsserver
800 ms
Per project
Measure
ts-r-lsp
tsserver
TypeScript 7 LSP
date-fns format/index.ts: first diagnostics
416 ms
timed out
168 ms
date-fns: keystroke to diagnostics p50 / p95
14.1 / 14.7 ms
timed out
5.0 / 5.8 ms
date-fns: memory, one file / all 1,641 open
164 / 232 MB
timed out
469 / 710 MB
RxJS merge-map.ts: first diagnostics
155 ms
953 ms
108 ms
RxJS: keystroke to diagnostics p50 / p95
12.2 / 12.8 ms
28.6 / 35.1 ms
13.3 / 17.2 ms
RxJS: memory, one file / all 231 open
138 / 377 MB
840 / 1,091 MB
397 / 820 MB
tRPC router.ts: memory, one file / all 154 open
95 / 165 MB
571 / 757 MB
477 / 480 MB
tRPC: hover p50 / p95
0.08 / 3.77 ms
0.75 / 9.66 ms
0.32 / 5.68 ms
tRPC: completion p50 / p95
0.08 / 0.25 ms
0.38 / 12.53 ms
0.22 / 0.40 ms
Diagnostics on the opened file (date-fns / RxJS / tRPC)
0 / 2 / 3
– / 0 / 0
0 / 0 / 2
How we measured
Measured
A scripted LSP client: first diagnostics, hover, definition and completion latency (20 sampled positions), keystroke to diagnostics (30 keys, 150 ms apart) on one file, then memory with that file open and with every source of the project open (5 s settle); one run per tool
Machine
Apple M-series MacBook (macOS arm64, 16 cores, 48 GB), shared with other jobs while measuring; release build, 4 threads
Software
ts-r-lsp release build with the ts-r backend and the tsc parity check off; each repo's own tsserver; TypeScript 7.0.2's native LSP (tsc --lsp) pinned in bench/package.json
Input
date-fns, RxJS and tRPC at the commits pinned in bench/repos.toml; the files and source directories are each repo's [repo.editor] set
Command
cargo xtask bench --fetch-repos --repos date-fns,rxjs,trpc && cargo xtask bench --editor --repos date-fns,rxjs,trpc (prints the commands; the editor-latency.js ones were run)
Lint in the editor: ts-r-lsp against the ESLint extension's server
Time from a keystroke to new lint diagnostics, and server memory, in tRPC's largest server source (22 KB, resolveResponse.ts) with the repo's own ESLint config and all 154 sources open. ts-r runs the rules it implements: 35 of the config's rules are not run in the editor (17 not implemented yet, 17 from plugins, 1 type-aware), so the ESLint server does more work and this is shown as a table rather than as bars.
Lint in the editor (not like-for-like: the ESLint server runs 35 rules ts-r skips)
Server
Keystroke to diagnostics, p50 / p95
RSS, all 154 sources open
ts-r-lsp --lint-only
15.6 / 15.8 ms (includes the default 10 ms debounce)
10.6 MB
ESLint server 3.0.34 (also runs the 35 rules ts-r skips)
53.3 / 58.6 ms
2,296 MB
How we measured
Measured
A scripted LSP client opens every source, then types 300 keystrokes 100 ms apart into a comment and times didChange to diagnostics; RSS of the server at the end; one run each
Machine
Apple M-series MacBook (macOS arm64, 16 cores, 48 GB), shared with other jobs while measuring; release build, 4 threads
Software
ts-r-lsp release build; the ESLint VS Code extension's server 3.0.34 run headlessly with pull diagnostics; the repo's own ESLint
Input
tRPC at the commit pinned in bench/repos.toml: packages/server/src/unstable-core-do-not-import/http/resolveResponse.ts, with packages/server/src and packages/client/src open
Command
scripts/limit.sh -- node editors/vscode/bench/lint-keystrokes.js ts-r target/release/ts-r-lsp target/bench-repos/trpc <file> --open-all --src-dirs packages/server/src,packages/client/src (eslint mode with eslintServer.js for the other)
ts-r-lsp: two editor windows on your own TypeScript
ts-r-lsp can also run your project's own TypeScript behind one shared server per workspace, instead of our checker. This measures total memory for two editor windows on tRPC in that mode (two files open in each, one window in packages/server and one in packages/client). The shared server holds both windows' projects, so it is larger than one plain tsserver but smaller than two.
Memory for two editor windowsShorter is faster, in MB
ts-r
Other tools
ts-r-lsp, one shared server698 MB
Two plain tsservers838 MB
VS Code default setup1,451 MB
Show as table
Memory for two editor windows (MB, lower is better)
Setup
Total memory
Notes
ts-r-lsp, one shared server
698 MB
2 editor fronts of 3 MB each, plus one daemon with one tsserver (692 MB)
Two plain tsservers
838 MB
one tsserver per window
VS Code default setup
1,451 MB
per window: semantic tsserver with automatic type acquisition, plus a syntax server
Time to first diagnostics in the same run: first window 1,252 ms (plain tsserver 856 ms), second window 5 ms (plain tsserver 548 ms).
How we measured
Measured
Total resident memory (RSS) of every process in each setup, summed with their children, after both windows have diagnostics for every open file; one run
Machine
Apple M-series MacBook (macOS arm64, 16 cores, 48 GB), shared with other jobs while measuring; release build, 4 threads
Software
TypeScript 6.0.3 (tRPC's tsserver) as the type backend
Input
tRPC at the commit pinned in bench/repos.toml; window A opens packages/server/src/unstable-core-do-not-import/router.ts and packages/server/src/index.ts, window B packages/client/src/index.ts and packages/client/src/links/httpBatchLink.ts
Time from starting the command to the program exiting, against tsx and Node's own type stripping. node -e 0 is the floor: starting Node with no TypeScript at all.
Run hello.tsShorter is faster, in ms
ts-r
Other tools
Baseline
node -e 0 (floor)23 ms
ts-r-run, warm cache29 ms
ts-r-run, empty cache32 ms
node --experimental-strip-types50 ms
tsx 4.2379 ms
Show as table
Run hello.ts (ms, lower is better)
Setup
Median time
node -e 0 (floor)
23 ms
ts-r-run, warm cache
29 ms
ts-r-run, empty cache
32 ms
node --experimental-strip-types
50 ms
tsx 4.23
79 ms
Run a 1,000-module programShorter is faster, in ms
ts-r
Other tools
Baseline
node -e 0 (floor)24 ms
ts-r-run, warm cache101 ms
ts-r-run, empty cache137 ms
node --experimental-strip-types215 ms
tsx 4.23270 ms
Show as table
Run a 1,000-module program (ms, lower is better)
Setup
Median time
node -e 0 (floor)
24 ms
ts-r-run, warm cache
101 ms
ts-r-run, empty cache
137 ms
node --experimental-strip-types
215 ms
tsx 4.23
270 ms
How we measured
Measured
Wall time, median of 15 runs
Machine
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
cargo xtask ecosystem runs each stage that applies to a package and compares it with the reference tool. Pass rate is pass / (pass + fail + error); skipped packages have nothing to compare. The check stage imports each package with skipLibCheck off and passes it when ts-r-check prints the same diagnostics (file, line, column, code) as tsc 7; in the 159 packages that fail, most diagnostics differ: 7,540 of the 8,339 compared differ. No package's own test suite passes with ts-r swapped in yet (0 of 4 selected).
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%
Show as table
Packages passing each stage (%, higher is better)
Setup
Pass rate
Pass / compared
Parse every file
99.9%
988 / 989
Bundle and run (vs esbuild)
92.2%
844 / 915
Transform TypeScript (vs tsc)
87.5%
42 / 48
Check an import of it (vs tsc 7)
77.6%
550 / 709
Own test suite
0%
0 / 4
Items inside the packages, and bundle size
Stage
Items compared
Items failing
parse (files)
39,101
1
transform (files)
1,156
6
bundle (entries)
1,217
77
check (diagnostics, ours and tsc's)
8,339
7,540
tests (suites)
4
4
Bundle size, 909 packages, minified
ts-r-build 102,531.6 KiB
esbuild 99,466.0 KiB (ts-r +3.1%)
How we measured
Measured
Pass, fail, error or skip per package per stage, compared against the reference tool's output
Machine
Not recorded with the result. ts-r's measured runs so far are on the project's Apple M-series development Mac (macOS arm64, release build).
Software
ts-r at commit cfbbe41; esbuild 0.28.2, Node 24.21.0, tsc 7.0.2
Input
The top 1,000 packages of ecosystem/packages.toml (list of 2026-10-14); one run of 546 s
Throughput of the shared engine parts, on public code. These have no comparison bars yet: the side-by-side parser benchmark against Oxc and esbuild is set up in bench/scenarios.toml but ts-r has no parse-only command for it yet.
What
Result
Measured on
Parse, single thread
about 225 MB/s (30,000 files/s)
tRPC including node_modules: 60,419 files, 456.5 MB; 4 files report syntax errors (not yet compared with tsc). Apple M-series shared laptop, 2026-10-16; command in crates/ts_r_parser/AGENTS.md.
Parse and bind, 4 threads
about 44,600 files/s (279 MB/s); bind alone about 85,000 files/s per thread
Shared cache, warm lookup of 10,000 entries (4 KiB each)
27 ms on one thread, 9.5 ms on all cores
cargo run --release -p ts_r_cache --example bench. Apple M-series. Commit 8d32516.
ts-r launcher overhead
about 0.5 ms (ts-r --version: 2.1 ms)
500 runs via Python subprocess, whose own spawn of /usr/bin/true is 1.6 ms median. Apple M-series. Commit 8d32516.
Correctness against tsc 7.0.2, esbuild and ESLint
Speed only counts if the output is right. These compare ts-r with the tool it replaces as the reference. The full list, generated from the crates' notes, is on the Compatibility and status page.
What
Result
Measured on
Module resolution
63,958 of 63,958 resolutions match (0 differences)
Every resolution in tsc --traceResolution for 24 tsconfig files of private-app. Commit 856e43d.
tsconfig loading
49 of 49 configs match tsc --showConfig exactly
private-app tsconfig files. Commit 856e43d.
JavaScript output (emit)
339 of 339 files match
private-app apps and packages, 15 tsconfig files. Commit e92e486.
JavaScript output (emit)
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 again
18,079 match, 0 differ
TypeScript's tests/cases (1,133 files with syntax errors skipped). Commit f3c5476.
Binder diagnostics
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 checker
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.
Not measured yet
The plan compares every tool against the one it replaces. These comparisons have no numbers 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.
ts-r-dev against Vite 8 on the generated 1,000 to 50,000-module apps.
The large public repos in bench/repos.toml (VS Code, Sentry, Grafana, Supabase, Backstage, n8n, cal.com, Next.js, React): they need a dedicated machine.
The VS Code editor-memory runs (stock VS Code against the ts-r extension) on the public repos.
Linux and Windows runs, and runs on a dedicated benchmark machine.
The raw data for this page is bench.json. Each tool’s page (Tools) draws the sections that belong to it.