ts-r-run
Run TypeScript with Node. Replaces tsx, ts-node.
- Pre-alpha
- Works from source
ts-r-run compiles the files an entry imports, caches them, and starts Node with a small preload that serves the compiled code. It replaces tsx and ts-node for scripts, servers and tests. Like them, it doesn’t check types.
2.7× faster runs
What switching looks like
Nothing is on npm yet. Once it is, switching looks like this: ts-r-run reads the config you already have, so the change is to the command, not the project.
"scripts": {
- "seed": "tsx scripts/seed.ts",
+ "seed": "ts-r-run scripts/seed.ts",
- "serve": "tsx watch src/server.ts",
+ "serve": "ts-r-run --watch src/server.ts",
}
What works, and what doesn’t yet
Works today
- .ts, .tsx, .mts and .cts entries, with ES modules and CommonJS in the same graph
- Enums, namespaces, parameter properties and TC39 decorators
- tsconfig paths and JSX settings; stack traces mapped back to TypeScript
- --watch, which restarts Node when a file in the graph changes
- A warm start that only checks file sizes and times before handing over to Node
- Emit that matches tsc 7 on every file of the reference app
Not yet
- The cache check doesn’t notice a new file that would change a resolution
- Only the entry’s tsconfig.json is used for every file, as with tsx
- Windows is untested
Measured
Every run, on the same reference app as the home page, with the command and commit that recorded it.
ts-r-run: running a TypeScript file
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.
- ts-r
- Other tools
- Baseline
- ts-r
- Other tools
- Baseline
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
- Command
cargo build --release -p ts_r_run --bin ts-r-run --example bench && TS_R_RUN_THREADS=4 scripts/limit.sh -- target/release/examples/bench --runs 15- Recorded in
- commit
e92e486
Correctness
Compared with the tool ts-r-run replaces, on its own tests and on real code.
- 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.
Command line
An excerpt of ts-r-run --help. You can also run it through the launcher as ts-r run.
Next to tsx and Node
ts-r-run needs nothing installed in the project and runs on the Node you already have. Unlike Node’s own type stripping, it handles enums, namespaces, parameter properties, decorators and tsconfig paths. Package imports stay with Node, so exports and runtime conditions behave exactly as they do without ts-r.
ts-r-run: run a TypeScript file with Node
Usage: ts-r-run [options] [node options] <file> [args...]
--watch Restart when a file of the module graph changes
--no-cache Compile everything again
--no-source-maps Faster start on large graphs
Needs Node 22.15+ (module.registerHooks).