Edited by humans. Written by AI. How our editing works
All articles

Script C Compiles TypeScript to Native Binaries

Vercel Labs' Script C compiles TypeScript to native binaries. The benchmark numbers are striking—but so is the history of projects that promised the same thing.

Mike Sullivan

Written by AI. Mike Sullivan

August 20, 20267 min read
Share:
Man wearing headphones makes a peace sign gesture while presenting three experiments about compiled TypeScript on a dark…

Photo: AI. Hayden Cross

Here is a sentence I have read, in various forms, since roughly 1997: if we just compile it properly, it'll be fast.

Borland said something like this about Pascal in the eighties. Sun said something like this about Java, repeatedly, before eventually giving us the Java Native Interface so you could escape the JVM when you needed actual speed. Mozilla said it about Asm.js in 2013—a subset of JavaScript so constrained it could be ahead-of-time compiled to near-native performance—before WebAssembly arrived to say the quiet part loud. Each of these projects was real, often technically impressive, and responded to a genuine problem. Most of them are not what you reach for when you start a new project today.

I want to hold that history in one hand while I tell you about Script C, because the history is context, not condemnation.

Script C is a Vercel Labs project that takes TypeScript and compiles it—genuinely compiles it, not transpiles-and-hopes—to either a C backend or LLVM IR, producing a static binary. The elevator pitch writes itself: TypeScript's developer experience, C's runtime footprint. ThePrimeagen, a developer and streamer who has spent years loudly cataloguing his complicated feelings about the JavaScript ecosystem, published a benchmark video this week putting Script C against Node and Bun across four tests. The numbers are striking enough that I think they're worth discussing, with some caveats about what "striking benchmark numbers in a 12-minute video" actually tells us.

What the tests showed

ThePrimeagen ran three progressively more demanding memory tests plus one adversarial workload. The methodology is straightforward—he explains his measurement approach using VMRSS and distributes results across percentile bands—but let me be direct: these are informal benchmarks conducted on a laptop and presented in a streaming video, not a controlled engineering study. Treat them as a directional signal, not a specification.

That said, the direction is notable.

In a minimum memory test—just launch the runtime, do nothing, take a snapshot—Node and Bun both carry significant baseline overhead from their respective engines. Script C, per ThePrimeagen's measurements, came in around 2.2 megabytes. The gap between Script C and either traditional runtime in this test is not close.

The object allocation test is where the technical story gets interesting. Script C can actually use TypeScript's type definitions to generate real C structs, with reference counting instead of garbage collection. The result, ThePrimeagen notes, is that a typed object in Script C's output is considerably smaller than what V8 or JavaScriptCore would allocate for the equivalent JavaScript object—he walks through the C output to show the struct representation directly. When you allocate a million of those objects, according to his measurements, Script C used around 88 megabytes versus roughly 260 for Node and 176 for Bun. The difference compounds at scale because the per-object savings compound at scale. That part of the story is structurally sound even if the exact figures need replication.

The startup time test is probably the most commercially legible result. ThePrimeagen measured how long it takes to start a server and accept a TCP connection: Node at roughly 56 milliseconds, Bun at roughly 15.8 milliseconds, Script C at roughly 2.3 milliseconds. And here is where the Vercel Labs parentage becomes obvious, because those are cold-start numbers. This project exists because someone at Vercel looked at what serverless functions cost per cold start and started asking uncomfortable questions.

"You could imagine a world in which these things are compiled behind the scenes," ThePrimeagen says in the video, "and now they're going from say tens of milliseconds down to just like ones of milliseconds. That's a big difference that actually makes cold starts significantly better."

He's not wrong about the arithmetic. Whether the arithmetic survives contact with real applications—which are not a simple server with one endpoint—is a different question, and one he acknowledges directly.

The fourth test was a WebSocket game server, running concurrent game sessions at load levels up to 1,600 simultaneous games (ThePrimeagen describes the setup as a 60-ticks-per-second game loop in his test design). Throughput performance was roughly equivalent across all three runtimes at those load levels—he admits he probably needed to constrain resources more aggressively to separate them. But memory consumption diverged significantly: Node at 170-plus megabytes at the P50 for 800 concurrent games, Script C at around 30 megabytes for the same load. That is not a rounding error in a graph. That is a different category of resource economics.

The calibration problem

I trust ThePrimeagen's technical instincts more than I trust the specific numbers in an informal benchmark. He's been doing this long enough to design tests that aren't embarrassing, and he's honest about where his methodology has gaps—the laptop constraint, the lack of CPU isolation, the caveat that real applications will behave differently. That intellectual honesty matters.

What I'd want to see before drawing stronger conclusions: the same tests run on isolated hardware, with real-world application code rather than synthetic workloads, over time, by people with no particular stake in the outcome. That is not an indictment of ThePrimeagen's video. It's just describing the distance between "interesting benchmark from a knowledgeable person" and "evidence I'd act on at production scale." We're at step one.

The Asm.js comparison is worth sitting with here. Asm.js benchmarks in 2013 were also striking—near-native performance for carefully written JavaScript subsets, demonstrated convincingly in controlled conditions. The problem was that real codebases don't look like benchmark code, that the toolchain friction was real, and that the performance advantages degraded as program complexity increased. Script C may navigate those problems better. It may not. The benchmark video doesn't answer that, and it doesn't pretend to.

The ecosystem question

Here's what I keep coming back to: the TypeScript ecosystem has had ample opportunity to treat types as more than editor hints, and it has, with remarkable consistency, preferred not to.

This is not an accident. The design choices that make TypeScript approachable—structural typing, optional strictness, the ability to type any your way out of trouble, the guarantee that valid JavaScript is valid TypeScript—are the same choices that make it structurally resistant to type-informed compilation. The type system was built to describe JavaScript, not to replace it. Compiling TypeScript to native code means making the type system do work it was specifically designed not to enforce at runtime.

I've watched this ecosystem debate performance versus flexibility since CoffeeScript was going to save us all from JavaScript's syntax and Node was going to make JavaScript a serious server language. The conclusion the ecosystem reliably reaches is: flexibility, please, and we'll add a linter to patch the worst of it. Every few years someone arrives with a more rigorous alternative—and the ecosystem says "neat, but could I still use any when things get complicated?" The answer with Script C, as with most strict compilation approaches, is "not really, no." That's the adoption wall this project will eventually meet.

ThePrimeagen closes with a telling line: "Hey, Vercel, I'll give you one. I did not like Zero, that language you created. At least I made fun of it. Sorry if it hurts your feelings, but this one—hey, it's at least a cool direction."

Coming from someone constitutionally inclined to be skeptical of Vercel's experimental language work, that's not nothing.

Script C is at Vercel Labs, which is where Vercel puts things that are real but not ready—a kind of institutional honest label. The benchmarks, gathered informally on one person's laptop and presented in a streaming video, are interesting in the way that early Asm.js demos were interesting: they prove the physics work. Whether the physics survive the messy conditions of actual software development is what the next year of engineering will determine.

The promise that compiling it properly will make it fast has been true before, and then complicated, and then retired, and then made again under a new name. Script C may be the iteration that breaks the pattern. Or it may be a very good answer to a question that the TypeScript ecosystem will collectively decline to ask.


Mike Sullivan covers the technology industry for BuzzRAG.

More Like This

Laptop displaying Unreal Engine 5.7 announcement with purple branding, surrounded by gaming figurines on wooden desk

Can Unreal Engine 5 Run on a $500 MacBook? Sort Of.

Testing Unreal Engine 5.7 on the MacBook Neo reveals what happens when professional software meets budget hardware—and why friction matters.

Mike Sullivan·4 months ago·5 min read
Cloudflare logo displayed centrally against shelves of colorful lava lamps with purple lighting backdrop

How Cloudflare Uses Lava Lamps to Encrypt the Internet

Cloudflare's San Francisco office has a wall of 100 lava lamps generating entropy for SSL/TLS encryption. Here's why computers can't be truly random.

Dev Kapoor·6 months ago·5 min read
Black HDMI 2.1 cable with gold connectors against grid background, labeled "8K & 4K 120 FPS" in bold text with red oval…

Do You Really Need an $80 HDMI Cable? Maybe Not

Tech reviewer Adam tests a premium HDMI 2.1 cable. We examine what you're actually paying for and whether most users need it.

Mike Sullivan·6 months ago·6 min read
Two tech professionals discuss TypeScript against a purple-lit modern office backdrop with GitHub logo and animated mascots

TypeScript's Journey: From JavaScript Fix to Go Boost

Explore TypeScript's evolution, its challenges, and why it's moving to Go for performance gains with insights from Anders Hejlsberg.

Mike Sullivan·7 months ago·3 min read
GitHub Podcast episode featuring three smiling guests against a vibrant gradient background with geometric shapes and the…

GitHub's Octoverse 2025: Vibe Coding & TypeScript Surge

Explore GitHub's Octoverse 2025: TypeScript's rise, AI's influence, and the unexpected return of COBOL.

Mike Sullivan·7 months ago·3 min read
TypeScript and Express logos with "Full Course" text on a dark blue digital background with a flame icon in the corner

Building Typed Express APIs with TypeScript

A freeCodeCamp tutorial walks through integrating TypeScript with Express—covering typed routes, middleware, and query params for production-ready APIs.

Dev Kapoor·4 weeks ago·6 min read
Neon-outlined game controller with d-pad, buttons, and analog stick on dark background with pixelated "SAVEPOINT" text below

Savepoint: The TDD Commit Tool You'll Actually Use

Tris Oaten's Savepoint CLI automates Git commits when tests pass. Mike Sullivan on why this small tool solves a surprisingly stubborn developer habit problem.

Mike Sullivan·3 months ago·7 min read
Man in business attire smiling at camera with "American Dynamism" text and American flag background on purple gradient design

Pax Silica: America's Answer to Belt and Road

The Trump administration's 14-country AI supply chain coalition sounds ambitious. Jacob Helberg makes the case—and the questions it raises are worth sitting with.

Mike Sullivan·3 months ago·7 min read

RAG·vector embedding

2026-08-20
1,772 tokens1536-dimmodel text-embedding-3-small

This article is indexed as a 1536-dimensional vector for semantic retrieval. Crawlers that parse structured data can use the embedded payload below.