Vercel Labs has released scriptc, an Apache-2.0 licensed TypeScript-to-native compiler hosted on GitHub. It compiles unmodified TypeScript — type-checked by the real TypeScript compiler — into self-contained native executables, with no Node, no V8 and no JavaScript engine in the default binary. A compiled hello-world-style program lands around 170-200 KB with roughly 2.4 ms startup, compared to about 47 ms for Node; typical RSS is 1-4 MB versus 67-116 MB for Node.
The compiler sorts every construct into three explicit tiers: statically compiled (the default), dynamically executed via an embedded quickjs-ng engine (~620 KB, opt-in with --dynamic) for things like npm dependencies' shipped JS or any-typed code, and rejected with a specific error code, code frame and usually a rewrite hint. A `scriptc coverage` command reports which statements compile statically and which blockers remain. Values crossing from dynamic back into static code are runtime-validated, so a lying type throws a catchable TypeError instead of corrupting memory.
The static surface covers classes with single inheritance and dynamic dispatch, closures, monomorphized generics, discriminated unions, async/await on stackful fibers, exceptions, destructuring, iterators, template literals and ECMAScript-exact regular expressions. The standard library includes UTF-16-exact strings, JS-exact arrays/Maps/Sets, JSON with runtime-validated casts, Math, typed arrays, Buffer and typed Error hierarchies. Much of Node's API surface is supported — fs, path, process, child_process, os, crypto, url, zlib, timers — plus the server stack (net, http, https, tls via vendored mbedTLS, dgram, dns, fs.watch, readline) and fetch with the WHATWG web subset over the native net/TLS stack. With --dynamic, npm packages resolve via Node's algorithm and are embedded at build time; binaries never read node_modules at runtime.
Correctness is enforced two ways: a differential test corpus of 800+ programs runs under both Node and the native binary with byte-for-byte matching stdout, stderr and exit codes, and the entire corpus re-runs under AddressSanitizer with a reference-count audit, where leaks and use-after-free are build failures. Documented, numbered divergences from Node exist (a few dozen, mostly timing internals and error-object properties); nothing diverges silently. Number formatting is shortest-roundtrip, fuzz-verified against Node on a million doubles.
Escape hatches include comptime(() => ...) for build-time evaluation baked in as literals, a native FFI (--ffi) binding signature-only TypeScript declarations to C ABI calls, and checked casts where JSON.parse(...) as Config inserts runtime validation that names the offending path. Architecturally, tsc parses and typechecks into a typed IR, from which an LLVM backend (default) or a readable C reference backend generates code compiled with clang. Installation is via `npm install -g scriptc`; clang is required, macOS arm64 is the primary platform, and Linux and Windows builds are cross-compiled with their own differential test lanes. The project is early-stage but has already drawn notable attention, reaching 750 stars on GitHub.
Comments
No comments yet — be the first.
Open the discussion
No account or password needed — just enter your e-mail and we’ll send you a one-time sign-in link. First time here? You’re set up automatically.
Your rating will be applied automatically after you sign in.
Check your inbox
We’ve sent a sign-in link to …. Open it on this device — this tab will sign you in automatically.
Waiting for your click …
·