Scope-B milestone NI-1, runtime side. Programs whose IR has a `nodeIsland.*` operation link scr_node_island.c and the SCR_NODE_ISLANDS build of scr_async.c; every other program links neither, byte for byte. - scr_node_island.c dlopens the bridge of a libnode pack on the first call (RTLD_NOW | RTLD_GLOBAL), checks its bridge ABI and that it links exactly the Node version recorded at build time, starts one Node environment and runs the embedded bootstrap (scr_node_island_host.cjs). A run that never calls into Node never maps libnode. The pack directory is SCRIPTC_LIBNODE at run time, else the recorded path; a `$ORIGIN/` path resolves against the executable's directory (the beside packaging, and the hook for shipping Node with the program). - scr_node_bridge.h is the C ABI between the runtime and the bridge; the runtime includes no Node or V8 header. The bridge (packages/libnode-common/bridge/scr_node_bridge.cc) initializes Node once with no default signal handling, no debug-signal handler or inspector, no stdio reinitialization and one platform worker, creates the environment from the built-in snapshot, routes Node's process exit to the runtime's exit sequence, promotes libnode to the global scope for native addons, and runs calls in a CallbackScope with a TryCatch. build-pack.mjs assembles a pack (libnode, the bridge, manifest.json) from a Node --shared build and the matching headers. - The SCR_NODE_ISLANDS build of scr_async.c adds a loop slot through which the runtime's loop drives Node's until NI-3 hosts the runtime's queues on Node's libuv: it keeps the program alive while Node has ref'd work, sleeps on Node's backend fd up to its next timer, and runs one non-blocking turn per loop turn. - The `nodeIsland` runtime feature (rule, link features, unit table, pack matrix row and scr_async.c variant), the nodeIsland.call/callSync libCalls, the install call in main, and the build-time record of the pack (node-islands/libnode.ts: --libnode=<pack>|beside or SCRIPTC_LIBNODE, SC8005 when none is usable, Node >=24.13.1). - The zero-cost gate and the bench nm test require that no good-code executable defines a Node island symbol. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
scriptc
scriptc compiles TypeScript and JavaScript to native executables and WebAssembly. It uses the types checked by the TypeScript compiler to generate machine code, and the output runs without Node.js installed. npm packages your program imports compile along with it. Code scriptc can't compile is reported at build time with a diagnostic and, where available, a rewrite hint.
scriptc is experimental and supports a subset of JavaScript, TypeScript, and Node.js APIs. Run scriptc coverage on an existing program to see how much of it compiles, and see the limitations and Node.js compatibility reference for details.
Installation
Install with Node.js 24 or later and npm:
$ npm install -g scriptc
The installed compiler runs natively on macOS, Linux, and Windows. Node.js is needed only to install it and to run WASI modules with scriptc run. Standalone compiler archives are also available from GitHub Releases.
Building executables requires a linker and the platform SDK or sysroot. See the quickstart for prerequisites and platform support for host requirements, cross-compilation, and WebAssembly.
Build a program
Create hello.ts:
const who = process.argv.length > 2 ? process.argv[2] : "world";
console.log(`hello, ${who}`);
scriptc run compiles the file and runs the result:
$ scriptc run hello.ts
hello, world
scriptc build writes an executable:
$ scriptc build hello.ts -o hello >/dev/null
$ ./hello scriptc
hello, scriptc
These examples use POSIX shell syntax. On Windows, build hello.exe and run it with .\hello.exe.
Use scriptc coverage hello.ts to check what compiles before you build. See coverage reports for details.
Use Node APIs
Supported Node APIs compile to the native runtime. For example, server.ts:
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 >/dev/null
$ ./server
listening on http://localhost:8080
Use npm packages
npm packages compile into the executable with your code, so it doesn't read node_modules at runtime.
Create cli.ts:
import pc from "picocolors";
console.log(pc.green("hello from scriptc"));
$ npm install picocolors
$ scriptc build cli.ts -o cli >/dev/null
$ ./cli
hello from scriptc
Package support is partial. See npm dependencies for which packages compile and how to check them.
Documentation
- Introduction: what scriptc is and what you can build.
- Quickstart: installation and your first executable.
- Coverage reports: check whether an existing program compiles.
- Platform support: cross-compilation and WebAssembly.
- CLI reference: commands, options, and output formats.
- Native program objects: use compiler output in external builds.
- Native FFI: call C ABI functions from compiled programs.
- WebAssembly modules: build and embed WASI modules.
- Examples: programs and integration examples in this repository.
Contributing
See CONTRIBUTING.md for source setup, testing, native artifact builds, and docs development.