Compile TypeScript to a Binary

One command turns main.ts into a standalone native executable. No Node.js on the target machine, no bundled runtime, no install step for your users.

terminal

$ perry compile main.ts

✓ Compiled executable: main (2.3 MB)

$ ./main

Hello, World!

Three things people call “compiling TypeScript”

When developers search for how to compile TypeScript to a binary, they usually run into three very different techniques that share one word:

  • Transpiling. tsc, SWC, and esbuild turn TypeScript into JavaScript. The output still needs Node.js, Bun, or a browser to run. No binary is involved.
  • Runtime embedding. bun build --compile, deno compile, and Node.js Single Executable Applications (SEA) concatenate your bundled JavaScript with a full copy of the runtime. You get a single file, but the engine rides along inside it and your code is still parsed and JIT-compiled every time the process starts.
  • Ahead-of-time native compilation. This is what Perry does. TypeScript is parsed with SWC, types are resolved, generics are monomorphized, and LLVM emits machine code. The linker produces a normal executable — the same class of artifact a Rust, Go, or C++ toolchain produces. There is no JavaScript engine in the binary at all.

Because there is no engine to boot and nothing to parse at startup, a Perry binary starts in about a millisecond. The pipeline itself is described in more depth on the TypeScript native compiler page and in the compiler internals.

How big is the binary?

Size depends on what you pull in, because only the code you actually use is compiled and linked:

  • A hello world is around 330 KB.
  • Typical CLI tools land at 2–5 MB.
  • Full applications that link large frameworks (Fastify, mysql2, and friends) are around 48 MB.

For contrast: a Node SEA executable is a copy of the node binary itself, so it starts at roughly 88–118 MB depending on platform before your code is added, and a Bun-compiled hello world measures about 60 MB on macOS arm64 and around 100 MB on Linux x64, because the entire Bun runtime is embedded.

Perry vs bun build --compile vs Node SEA

All three give you a single file you can hand to someone. They are otherwise very different tools, and each is the right answer for someone:

Perrybun build --compileNode SEA
What it producesAOT-compiled machine code (LLVM)Bundled JS + embedded Bun runtimeCopy of the node binary with your bundled script injected
Execution modelNative code, no JS engineJIT (JavaScriptCore) at run timeJIT (V8) at run time
Hello-world size~330 KB~60 MB (macOS arm64) to ~100+ MB (Linux/Windows)~88–118 MB (size of the node binary)
Startup~1 ms~10 ms~30 ms
Cross-compilation10 targets, including Windows/macOS/iOS from LinuxYes — Linux, Windows, macOS via --targetNo — copy a per-platform node binary instead
JS/npm compatibilityGrowing: axios, zod v4, express, fastify, hono compile natively; optional V8 fallback for the restFull — it is the Bun runtimeFull Node semantics; requires pre-bundling, CommonJS-only on Node 24 LTS
StatusPre-1.0Stable“Active development” stability in Node 24 LTS

The honest framing: if your application leans on the full npm ecosystem and you want zero compatibility risk, Bun and Node SEA run exactly the engine semantics you already develop against — that is their strength, and the size cost may not matter for your deployment. Perry is a different trade. You get true ahead-of-time compilation, small binaries, and millisecond startup; in exchange you adopt a pre-1.0 compiler whose JavaScript conformance is measured and published (test262: String 79%, Array 72% as of v0.5.1146) rather than inherited from V8.

Detailed head-to-heads: Perry vs Bun and Perry vs Deno. For how npm packages compile, see Real npm packages and a conformance sweep.

Performance Comparison

Native compilation delivers unmatched efficiency

MetricPerryNode.jsBun
Binary Size2-5 MB~80 MB~90 MB
Startup Time~1 ms~30 ms~10 ms
Runtime DependenciesNoneNode.jsBun
Memory OverheadMinimalV8 + GCJSC + GC

Benchmark Results: Up to 18x Faster

Perry v0.5.279 vs Node.js v25 — RUNS=11 median, Apple M1 Max (lower is better)

accumulate
18x
object create
11x
json roundtrip
5.3x
loop overhead
4.5x
math intensive
3.6x
array read
3.3x
fibonacci
3.2x
array write
2.3x
loop data dependent
1.4x
nested loops
1.0x
Binary SizeLower is better
Perry
5 MB
Node.js
80 MB
Bun
90 MB

Compile your first binary today

Install with Homebrew, APT, or winget — then perry compile main.ts.