scriptc: Compile TypeScript to Native Executables
GitHub Repo
Apache-2.0
October 2, 2026 at 09:19 AM
0 views

scriptc: Compile TypeScript to Native Executables

@vercel-labsProject Author

What scriptc is

scriptc is a compiler that turns TypeScript and JavaScript into native executables and WebAssembly modules. Rather than bundling a script together with a full JavaScript runtime, it uses TypeScript's type information to compile supported code to native instructions. A program that compiles fully statically produces a binary that runs without Node.js and without any JavaScript engine inside it.

For code that cannot be compiled statically, such as npm dependencies or any-typed code, a --dynamic flag embeds the quickjs-ng engine and includes the dependency JavaScript at build time. The result still ships as a single executable that does not read node_modules at runtime.

The project is published by Vercel Labs and carries a "Labs experiment" badge. Its README is clear that scriptc is experimental and supports a subset of JavaScript, TypeScript and Node.js APIs. It is aimed at TypeScript developers who want small, self-contained binaries for CLIs, servers and embedded use, and who are willing to work within the compiler's supported subset.

How it works

The compiler runs natively on the host and bundles its own TypeScript checker and an LLVM helper. It type-checks the program, lowers statically typed code to LLVM, and links the resulting program object against a precompiled runtime pack that implements the supported Node.js APIs. Values use native representations: records have exact native layouts, strings are UTF-8 with an explicit length, and unions are tagged.

According to the platform docs, the runtime has native backends for the event loop (epoll on Linux, kqueue on macOS), the HTTP server stack, TLS and fs.watch, and its behavior is checked against real Node.js in differential test lanes on Linux, Alpine and Windows. The Windows lanes exercise net, http, https, tls, http2, dgram, dns and a native fetch implementation.

Outputs selected with --emit=ir|llvm|asm|obj need no Node installation or external toolchain. Full executables additionally need the platform linker and SDK or sysroot. Cross-compilation uses optional @scriptc/runtime-<target> packages plus zig for Linux, Windows and WASI linking, with the target chosen through SCRIPTC_TARGET.

Because static compilation is all-or-nothing per operation, scriptc includes a coverage command that reports which statements compile statically, which need the dynamic engine, and which are unsupported. Build errors use SC codes with source locations and, where available, rewrite hints.

Key features

  • Type-directed native compilation: statically typed TypeScript compiles to native code through LLVM, with no JavaScript engine in fully static builds.
  • Optional embedded engine: --dynamic adds quickjs-ng for npm packages and any-typed code, with dependency JavaScript embedded at build time.
  • Node.js API support: supported Node APIs such as node:http compile to the native runtime; a compatibility reference lists support separately for static and engine-executed code.
  • Coverage reports: scriptc coverage analyzes a program without building it and lists dynamic or unsupported sites.
  • Cross-compilation: Linux arm64 and x86_64 (glibc and musl), Windows x86_64 and WASI from one host using runtime packs and zig.
  • WebAssembly output: SCRIPTC_TARGET=wasm32-wasi produces standalone WASI Preview 1 modules.
  • Library mode for mobile: iOS device, iOS simulator and Android arm64 targets build static archives with --lib for an app to link.
  • Native FFI: compiled programs can call C ABI functions.
  • Native program objects: compiler output can be fed into external builds.
  • Native debugging: --optimization=dev builds support source breakpoints and native stack frames; macOS builds produce a .dSYM bundle.
  • Windows GUI subsystem: --windows-subsystem=gui avoids an extra console window for windowed apps.

Getting started

Install with Node.js 24 or later and npm. The installed compiler itself runs natively, and standalone archives are also available from GitHub Releases:

$ npm install -g scriptc

Create hello.ts:

const who = process.argv.length > 2 ? process.argv[2] : "world";
console.log(`hello, ${who}`);

Compile and run in one step:

$ scriptc run hello.ts
hello, world

Or build a standalone executable:

$ scriptc build hello.ts -o hello
$ ./hello scriptc
hello, scriptc

A small HTTP server using Node APIs compiles the same way:

import { createServer } from "node:http";

const server = createServer((req, res) => {
  res.setHeader("content-type", "application/json");
  res.end(JSON.stringify({ path: req.url }));
});

server.listen(8080, () => {
  console.log("listening on http://localhost:8080");
});
$ scriptc build server.ts -o server
$ ./server
listening on http://localhost:8080

For an npm dependency, enable the embedded engine:

$ npm install picocolors
$ scriptc build cli.ts --dynamic -o cli
$ ./cli
hello from scriptc

On macOS, executable builds need the Xcode Command Line Tools; the quickstart lists macOS 15+ (arm64 or x64), Linux (arm64 or x64) and Windows x64 as supported hosts.

Use cases

  • Distributing CLIs: ship a TypeScript command-line tool as one binary that users can run without installing Node.js.
  • Small server binaries: compile an node:http service into an executable for minimal containers, including static musl builds for Alpine.
  • WASI modules: produce .wasm modules from TypeScript for WASI runtimes and embedders.
  • Embedding in mobile or native apps: build library-mode archives for iOS and Android with declared exports and host callbacks.
  • Interop with C: call C ABI functions through native FFI, or link program objects into an existing native build.
  • Gradual adoption: run scriptc coverage on an existing codebase to see how much would compile statically before committing to it.

How it compares

The README does not compare scriptc to other tools. In the same broad category, Node.js single executable applications, Bun's and Deno's compile commands package a script with a full JavaScript runtime, which gives broad compatibility at the cost of binary size and runtime overhead. scriptc takes a different route: ahead-of-time native compilation of typed code, with an embedded engine only when you opt in. That tradeoff means much stricter language support. Projects such as AssemblyScript also compile a TypeScript-like language to WebAssembly, but use their own dialect, whereas scriptc targets standard TypeScript and Node.js APIs within its supported subset.

Things to know before adopting

  • Experimental subset: the limitations page documents many unsupported forms in static code, including object-to-primitive loose equality, some generic patterns, async yield* delegation, computed dynamic imports, and certain union and record-shape conversions. Passing a record with extra fields where a narrower shape is expected can produce an SC2002 error.
  • --dynamic is not a fallback for everything: enabling it does not add support for unsupported statically typed calls.
  • Toolchain requirements: executables need a platform linker and SDK; cross-linking needs zig; GNU/Linux builds require glibc 2.34 or newer.
  • Debugging limits: TypeScript expression evaluation and stepping through code in the embedded engine are not supported in the debugger.
  • Very new: the repository was created in July 2026, so APIs and supported features are likely to shift.
  • License: Apache-2.0.

Project activity

As of October 2026 the repository has roughly 5,900 stars on GitHub. It was created on July 22, 2026, is written in TypeScript, and is licensed under Apache-2.0. The compiler is distributed on npm as scriptc and through GitHub Releases. Source code is at github.com/vercel-labs/scriptc, and documentation, including the limitations and Node.js compatibility reference, is at scriptc.dev.

Enjoying this project?

Discover more amazing open-source projects on TechLogHub. We curate the best developer tools and projects.

Project
scriptc
Created
October 2
Last Updated
October 2, 2026 at 09:19 AM

Find more projects like this

One email a week: new and trending developer tools, fresh comparisons, and what shipped. Unsubscribe in one click.