scriptc | TypeScript-to-Native Compiler<br>450
macOS · Linux · Windows<br>TypeScript-to-Native Compiler<br>Ordinary TypeScript becomes a small, fast native binary — no Node, no V8, no JavaScript engine required. What compiles behaves byte-for-byte like Node.<br>Get StartedGitHub
fib.ts — compiled with scriptc<br>div]:my-0! [&>div]:rounded-none! [&>div]:border-none! [&>div]:bg-transparent!">$ cat fib.ts<br>function fib(n: number): number {<br>return n<br>console.log(fib(30));
$ scriptc run fib.ts<br>832040
$ scriptc build fib.ts -o fib && ./fib<br>832040
Three tiers, always explicit<br>Every construct in your program lands in exactly one tier, and the tier is the promise.<br>Tier 1<br>Compiled statically<br>The default. Ordinary TypeScript — classes, closures, async/await, the stdlib, Node's fs/path/process/http surface — becomes native code with no engine in the binary. What compiles behaves byte-for-byte like Node.
Tier 2<br>Runs dynamically<br>Opt in with --dynamic: an embedded JavaScript engine (~620KB) executes what can't be static — npm dependencies' shipped JS, any-typed code. Every value crossing back into static code is validated at runtime.
Tier 3<br>Rejected at compile time<br>Everything else fails the build with a specific error code, a code frame, and usually a rewrite hint. Nothing is ever silently miscompiled.
Staticness you can see<br>Most TypeScript is far more static than the ecosystem assumes. scriptc decides, construct by construct, what can compile to native code — and tells you. A binary never silently grows an engine: the dynamic tier is opt-in, and the coverage report names every site that needs it.<br>Reading coverage reports →<br>$ scriptc coverage cli.ts
statements analyzed 4<br>compile statically 3 (75%)
runs with --dynamic 2 sites (embeds a JS engine, ~620KB — static stays the default)<br>×1 importing 'picocolors' requires the embedded dynamic engine — the package's implementation runs there SC2013
No code changes<br>No annotations, no dialect, no special stdlib. The same TypeScript you run on Node, type-checked by the real TypeScript compiler.
Small and fast<br>A hello-world binary is ~320KB, starts in about 4ms, and links against nothing but libSystem. Node needs a ~120MB runtime and ~35ms to print the same line.
Measured coverage<br>scriptc coverage tells you, statement by statement, what compiles statically, what needs the dynamic engine, and exactly what blocks the rest.
Differentially tested<br>Every corpus program runs under Node and as a native binary; stdout, stderr, and exit codes must match byte-for-byte. The whole corpus re-runs under AddressSanitizer.
Compile your first binary<br>Clone the repository, build the compiler, and turn a TypeScript file into a native executable in a couple of minutes.<br>QuickstartIntroduction