Scriptc by Vercel: The TypeScript-to-Native Compiler That Removes JavaScript Engines
If you have ever built a command-line tool (CLI) or a microservice in Node.js and tried to ship it to a friend or a server, you know the pain. You send the code, and they reply, "But do you have Node.js installed?" or "Why is the download 200MB?"
For years, the standard answer was "just install Node" or "use a Docker container." But there is a third way that is gaining serious traction in the ecosystem, thanks to experimental work from Vercel Labs.
Enter Scriptc, a TypeScript-to-native compiler that turns your .ts files into standalone executables—binaries that contain no JavaScript engine and no runtime overhead.
In this tutorial, I will walk you through what Scriptc is, why it matters for the future of JavaScript tooling, and how you can start compiling your first TypeScript project into a native binary today.
The Problem with Node.js Distribution
To understand why Scriptc is significant, we have to look at how we currently distribute JavaScript applications.
The "Runtime" Tax
When you create a Node.js application, your code is just text. To run it, you need the Node.js runtime (V8 engine). When you want to share your tool with a non-developer, you usually have two options:
- Source Distribution: Send the code. The user must install Node.js, run
npm install, and hope their environment matches yours. This is fragile and user-hostile. - Bundling (e.g.,
pkg,nexe): Bundle your code with the Node.js executable. This works, but it results in bloated binaries (often 30MB–60MB) because you are shipping the entire V8 engine just to run a few lines of logic.
The Docker Alternative
Docker solves this perfectly for production, but it is overkill for a simple CLI tool. If I want to give you a script that checks the weather, I shouldn't need to ask you to install a container runtime.
This is where a TypeScript-to-native approach changes the game.
What is Scriptc?
Scriptc is a compiler developed by Vercel Labs that transpiles TypeScript directly into C++ source code, which is then compiled into a native binary using standard system compilers like GCC or Clang.
The key distinction here is the absence of a JavaScript engine in the final binary.
Unlike tools that wrap your code in a Node.js runtime, Scriptc compiles your logic into efficient machine code. This results in:
- Tiny Binaries: Often just a few megabytes.
- Instant Startup: No time wasted booting an interpreter.
- Zero Dependencies: The user doesn't need Node.js, Python, or anything else installed.
This project is a significant step toward treating JavaScript and TypeScript as first-class citizens for systems programming, not just web scripting.
Prerequisites
Before we dive in, make sure you have the following installed on your machine:
- Node.js (v18+): Needed to run the compiler itself.
- A C++ Compiler: GCC or Clang. Scriptc generates C++ code, so you need a toolchain to compile it.
- A Code Editor: VS Code is recommended, though any editor works.
Tip: If you are organizing your migration from Node.js to native tools, consider using **Notion* to track your project roadmap and documentation.*
Installation and Setup
Getting started with Scriptc is straightforward. Since it is part of the Vercel Labs ecosystem, you can install it via npm.
1. Initialize Your Project
First, create a new directory for your project. You can host the source code on GitHub once you are ready to share it.
mkdir scriptc-demo
cd scriptc-demo
npm init -y
2. Install Scriptc
Install the compiler as a development dependency:
npm install --save-dev @vercel/scriptc
You will also need TypeScript:
npm install --save-dev typescript
3. Configure TypeScript
Create a tsconfig.json file. Scriptc is strict about types, so ensure you have strict mode enabled.
{
"compilerOptions": {
"target": "ES2020",
"module": "commonjs",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src/**/*"],
"exclude": ["node_modules"]
}
Writing Your First Scriptc App
Let's write a simple HTTP server. This is a common use case for Node.js, but we are going to compile it into a native binary that runs without the Node runtime.
Create a file at src/index.ts:
import http from 'http';
const PORT = process.env.PORT || 3000;
const server = http.createServer((req, res) => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
if (req.url === '/') {
res.end('Hello from a Native Binary! 🚀\n');
} else if (req.url === '/info') {
res.end(`Running on port ${PORT}\n`);
} else {
res.writeHead(404);
res.end('Not Found\n');
}
});
server.listen(PORT, () => {
console.log(`Server listening on port ${PORT}`);
});
Note that we are using standard Node.js APIs (http, process). Scriptc provides polyfills or native implementations for these core modules, allowing you to write standard TypeScript code while getting native performance.
Building the Binary
Now for the magic moment. We need to configure our package.json to include a build script.
Open package.json and add the following to the scripts section:
"scripts": {
"build": "scriptc build",
"start": "node dist/index.js",
"dev": "ts-node src/index.ts"
}
Now, run the build command:
npm run build
You should see output indicating that Scriptc is transpiling your TypeScript to C++ and then invoking your system compiler.
Scriptc v0.1.0
Compiling src/index.ts...
Generating C++ source...
Compiling with g++...
Binary created: dist/scriptc-demo
Running the Native Binary
Unlike a Node.js app where you run node index.js, with Scriptc, you simply run the binary directly.
./dist/scriptc-demo
If you are on Windows, it will be dist\scriptc-demo.exe.
Open your browser and go to http://localhost:3000. You should see "Hello from a Native Binary! 🚀".
Check the file size of your binary. Compare it to a traditional Node bundle. You will likely find Scriptc produces a significantly smaller executable because it doesn't carry the weight of the V8 engine.
How Scriptc Works Under the Hood
It is worth understanding the pipeline so you know what you are building.
- TypeScript Parsing: Scriptc reads your
.tsfiles and parses them into an Abstract Syntax Tree (AST). - Intermediate Representation (IR): The AST is converted into an intermediate representation. This step handles type checking and optimization.
- C++ Generation: The IR is transpiled into C++ source code. This is where Scriptc maps JavaScript concepts (like dynamic typing and garbage collection) to C++ equivalents.
- Native Compilation: Finally, a standard C++ compiler (like GCC, Clang, or MSVC) compiles the generated C++ into a native executable.
This architecture allows Scriptc to leverage the massive ecosystem of C++ compilers, meaning your binary will be optimized for the specific OS and architecture you are building on.
Practical Use Cases
When should you use Scriptc? It isn't a replacement for Node.js for everything, but it shines in specific areas.
1. CLI Tools
If you are building a developer tool (like create-react-app or eslint), distributing a native binary removes friction. Your users don't need to configure their environment.
2. Edge Functions and Serverless
While Vercel has its own optimized runtime for serverless functions, the concept of
Enjoyed this? I build simple, powerful AI tools — try the free Text Summarizer or browse the full toolkit at Solomon Tools. No signup, no subscription.
Top comments (0)