
Who scriptc is for#
TypeScript developers shipping CLI tools as native binaries
scriptc produces a single native binary from a TypeScript source file that users can download and run without installing Node.js. The binary starts in ~4ms and is roughly 320KB for typical programs. Standard Node APIs for filesystem operations and process management compile to the static tier, so CLI tools using those APIs get the full size and speed benefit.
Skip if:
Your CLI depends heavily on npm packages with complex JavaScript internals. The --dynamic flag handles this, but each package that cannot compile statically adds to the dynamic tier and the size advantage over Node SEA narrows.
DevOps engineers distributing automation utilities
TypeScript DevOps scripts that use Node's fs, path, process, and http APIs compile to native binaries that run on servers without any Node.js installation. Distributing a utility as a single executable removes the need to install a Node.js version, manage package dependencies, or ship node_modules to target hosts.
Skip if:
Your automation code relies on many npm packages. Run scriptc coverage to check how much stays in the static tier before committing; heavy npm usage may reduce the size benefit significantly.
Developers building server programs as single native binaries
HTTP servers using Node's createServer API compile to native executables. A single binary server requires no runtime on the deployment host, simplifies container images, and starts faster. The WASI target extends the same TypeScript source to portable WebAssembly modules that run on any WASI-compatible runtime.
Skip if:
Your server application uses Express, Fastify, or other npm framework code. These require --dynamic, which embeds the JS engine. The binary is still smaller than a Node SEA bundle but the pure-native advantage narrows.
Developers studying TypeScript native compilation
scriptc makes the compilation process observable. The --emit flag stops the build at any intermediate stage: typed IR, C, LLVM IR, assembly, or object files. The coverage report shows statement-by-statement which constructs compile statically. The differential testing design means you can validate that a compiled program matches Node behavior by construction.
Skip if:
You need a stable, production-hardened toolchain for shipping software. scriptc is a Vercel Labs experiment with an active development pace; treat its API as potentially unstable between releases.
The problem it solves#
TypeScript developers who want to distribute CLI tools or server programs face a bundle problem: every established packaging approach ships the full Node.js runtime inside the binary. Node.js Single Executable Applications and similar tools work this way, producing files of 100MB or larger that take 35ms or more to start. The binary carries a complete V8 engine and the full Node runtime even when the program's own logic is entirely static TypeScript.
The workaround is either to require end users to install Node.js themselves, switch to Go or Rust and rewrite existing TypeScript code, or accept the size and startup penalty. Each path has real cost: requiring Node.js complicates distribution and installation scripts; rewriting in another language is expensive for established codebases; and binaries over 100MB are impractical for constrained deployment targets like minimal containers or environments with strict storage limits.
How it solves it#
Three-tier compilation model
Every TypeScript construct lands in exactly one tier at compile time. Tier 1 compiles to native code: classes, closures, async/await, and Node's fs/path/process/http surface. Tier 2 opts in to an embedded JavaScript engine (quickjs-ng, ~620KB) for npm packages and any-typed code via --dynamic. Tier 3 rejects at compile time with a specific error code, a code frame, and usually a rewrite hint. Nothing is silently miscompiled.
Static coverage reporting
scriptc coverage analyzes a TypeScript file statement-by-statement and reports how much compiles statically versus how much would require the dynamic engine. The report names every site that needs dynamic execution and gives a diagnostic code. This shows before building whether --dynamic is necessary and exactly which imports drive that requirement. Run it before committing to a --dynamic build to understand the binary size impact.
Native Node API support
The supported subset of Node's built-in APIs (fs, path, process, http) compiles directly to native code without any JavaScript engine. HTTP servers written with Node's createServer API compile to native binaries that listen on a port without any runtime dependency on the target host. The full set of supported APIs is documented at scriptc.dev/platforms.
Differential testing against Node behavior
Every program in the test corpus runs under Node and as a compiled native binary; stdout, stderr, and exit codes must match byte-for-byte. The full test suite also runs under AddressSanitizer. This means the compiler's correctness is continuously validated against the reference Node interpreter, not just unit-tested in isolation. The approach gives confidence that a program that runs on Node will behave identically when compiled.
Multiple output formats
Beyond native executables, scriptc build can stop at any intermediate stage: typed IR, readable C, textual LLVM IR, native assembly, or a relocatable object. The --emit flag controls the stage. Stopping at C or LLVM IR lets you inspect what the compiler generates, use the output in custom toolchains, or link it into larger build systems. Each output kind accumulates in the .scriptc/ directory.
WebAssembly target via WASI
With Zig installed and the SCRIPTC_CC and SCRIPTC_TARGET environment variables set, the same TypeScript source compiles to a portable WASI Preview 1 module. The WASI target supports the same language tiers as native targets: async/await, promises, generators, timers, and filesystem callbacks. Network APIs, child processes, and OS signals fail before linking with error code SC3002 because they require capabilities absent from portable WASI Preview 1.
Strengths and trade-offs#
Strengths
- Binary size orders of magnitude smaller than Node bundlesA hello-world binary is ~320KB and links against nothing but libSystem. The equivalent Node.js Single Executable Application carries a 120MB+ runtime for the same program. For CLI distribution, the difference is downloading ~320KB versus 120MB or more. Startup time follows the same pattern: ~4ms for scriptc binaries versus ~35ms for Node. Both figures come from the official scriptc benchmark on the product website.
- Apache-2.0 license permits commercial distributionscriptc is Apache-2.0 licensed, which permits use, modification, and commercial distribution of both the compiler and the programs it produces without additional restrictions. Apache-2.0 does not impose copyleft requirements on distributed binaries, making it compatible with commercial software distribution. The binaries scriptc produces require no Node.js at runtime, removing the Node runtime from the dependency footprint of distributed applications.
- Correctness validated against Node behaviorThe differential testing approach runs every corpus program under Node and as a native binary, comparing stdout, stderr, and exit codes byte-for-byte. An AddressSanitizer pass over the native runtime catches memory errors as a separate gate. This is a stronger correctness guarantee than tools that test compilation behavior in isolation from the reference interpreter.
- No code changes required to existing TypeScriptThe same TypeScript source checked by the real TypeScript compiler compiles with scriptc without modification. No annotations, no special dialect, no custom standard library. The TypeScript compiler handles parsing and type checking; scriptc uses the resulting type information for code generation. Existing TypeScript projects can be tried with scriptc by running scriptc coverage to assess how much compiles statically before committing.
Trade-offs
- -Experimental Vercel Labs project with no stability commitmentscriptc is labeled a Vercel Labs experiment and was first published in July 2026. It does not carry a stability or API commitment typical of a production release. With 55 open issues at listing time and a very recent creation date, the toolchain is under active development and its surface may change between releases. Evaluate the experimental status against your project's tolerance for toolchain churn before building on it.
- -Node.js 24+ required at build timeThe compiler itself requires Node.js 24 or newer to run. This is strictly a build-time requirement: the compiled binaries run without any Node installation. But it means build environments must carry a recent Node.js version; projects still on older Node versions need a toolchain upgrade before using scriptc.
- -Dynamic tier adds an embedded JS engine to the binaryWhen --dynamic is needed for npm packages or any-typed code, the binary includes the quickjs-ng engine at ~620KB. This is still far smaller than a Node SEA bundle, but it is not zero-cost. Use scriptc coverage before building to understand how much of a dependency tree requires the dynamic tier and whether the size trade-off fits the deployment context.
- -Executable builds require a platform linkerCompiling to a runnable native executable (beyond emitting IR or C) requires a platform linker driver and SDK on most platforms. macOS 15+ arm64 uses a bundled helper automatically; other targets need clang or an equivalent. The SCRIPTC_LINKER environment variable selects the linker driver. The README documents the exact requirements per platform, including the WASI path via Zig.
scriptc vs alternatives#
scriptc vs Node.js Single Executable Applications
Node.js Single Executable Applications (SEA) and scriptc both produce self-contained distribution artifacts from TypeScript programs, but the approaches differ fundamentally. Node SEA bundles the full V8 engine and Node.js runtime into the executable; scriptc compiles TypeScript to native machine code with no engine in the binary for programs that fit the static tier.
| Feature | scriptc | Node.js SEA |
|---|---|---|
| Binary size (hello-world) | ~320KB | 120MB+ |
| Startup time | ~4ms | ~35ms |
| Runtime required at deployment | No | No |
| npm package support | Via --dynamic (+620KB) | Built-in |
| WASI/WebAssembly target | Yes | No |
| Project status | Experimental | Stable (Node LTS) |
scriptc is the better choice when binary size directly matters: distributing CLI tools to users who download them, deploying to minimal containers, or shipping to environments where a 120MB binary is impractical. The ~4ms startup advantage matters for CLI tools called in tight loops or automation scripts. Node SEA is the better choice when you need a production-stable path, full npm ecosystem compatibility without the dynamic-tier trade-off, and tooling backed by the Node.js LTS schedule.
scriptc vs Rewriting TypeScript Logic in Go or Rust
Before native TypeScript compilation was possible, teams that needed native binaries from TypeScript codebases had two paths: bundle Node with the output or rewrite the relevant code in Go or Rust. scriptc offers a third option for programs that stay within the supported TypeScript subset. The trade-off is a younger, experimental toolchain versus the stable, production-tested ecosystems of Go and Rust. For teams with significant existing TypeScript code, avoiding a language rewrite is a concrete benefit; for greenfield projects where native performance is the primary goal, Go or Rust remain the more predictable choice.
Quick start#
Install scriptc as a global npm package; Node.js 24 or newer is required at the build step.
```bash
npm install -g scriptc
scriptc run hello.ts
scriptc build hello.ts -o hello
```What it's built on#
- Languages
- CJavaScriptTypeScript
- Frameworks
- Next.jsReact
FAQ#
Does scriptc require Node.js to run the compiled binaries?
No. Compiled native executables require no Node.js installation on the target machine. Node.js 24 or newer is required only on the build machine to run the scriptc compiler itself. The binaries it produces link against nothing but libSystem and carry no external runtime dependency.
How does scriptc handle npm packages?
npm packages that ship JavaScript cannot compile to the static tier. Pass --dynamic when building to embed them: scriptc bundles the package's JavaScript in the executable using quickjs-ng (~620KB). The binary does not read node_modules at runtime; everything is resolved and bundled at build time. The scriptc coverage command shows which imports would require --dynamic before you build.
Which Node.js built-in APIs does scriptc support natively?
The supported APIs include fs, path, process, and http, which compile to native code in the static tier. APIs unavailable in the static tier fail with a specific diagnostic code. In the WASI target, network sockets, child processes, and OS signals fail before linking with error SC3002. The full compatibility table is at scriptc.dev/platforms.
Is scriptc ready for production use?
Not yet. scriptc is a Vercel Labs experiment first published in July 2026. It carries no stability or API commitment typical of a production tool. There are 55 open issues at listing time, and the project is under active development. It is worth evaluating for projects where native TypeScript compilation fits, but treat its API as potentially unstable between releases.
Can scriptc compile TypeScript to WebAssembly?
Yes, via the WASI Preview 1 target. Install Zig, set SCRIPTC_CC=zigcc and SCRIPTC_TARGET=wasm32-wasi, then run scriptc build. The WASI target supports async/await, timers, generators, and filesystem operations. Network APIs, child processes, and OS signals fail before linking with error SC3002 because they require capabilities absent from the portable WASI specification.
Similar open-source tools#
FckSignups
Open-source tools that work instantly, no signup required
Cyrus
Systems language: manual memory, no GC, LLVM-native compilation
limen
Composable authentication for modern Go backends
Neovim
Hyperextensible Vim-based editor with Lua plugin support
Modelence
Full-stack framework for building production-ready web apps
CodeEdit
Native Swift code editor for macOS with no Electron overhead

