A TypeScript Native Compiler, Built in Rust

Perry compiles the TypeScript you already write to machine code — the way a Rust or Go toolchain compiles its language. No transpiled JavaScript, no virtual machine, no runtime on the target system.

Not a transpiler. Not a runtime.

Most TypeScript tooling falls into two families. Transpilers — tsc, SWC, esbuild — check and strip the types, then emit JavaScript for an engine to execute later. Runtimes — Node.js, Bun, Deno — are those engines: they parse, interpret, and JIT-compile the JavaScript every time your program starts.

A native compiler is the third family, and for TypeScript it has been mostly empty. Perry treats type annotations not as documentation to be stripped but as the input that drives code generation. The result of perry compile main.ts is a standalone executable containing machine code — typically 2–5 MB, starting in about a millisecond.

How It Works

From TypeScript source to native executable in seconds

TypeScript.ts files
SWC
ParserFast parsing
HIR
TransformMonomorphization
LLVM
CodegenMachine code
Executable2-5 MB binary

Want to know how the compiler works under the hood? Compiler internals

Deep dive: TypeScript on LLVM — monomorphization, NaN-boxing, and why Perry left Cranelift.

The pipeline, step by step

  1. Parse (SWC). Source files are parsed with SWC, the Rust-native TypeScript parser, so even large projects parse in milliseconds. Module codegen, transform passes, and symbol scanning run in parallel across cores.
  2. Type resolution. The compiler resolves declared types and infers the rest, giving every expression a concrete type before code generation begins.
  3. Typed HIR & monomorphization. The AST is lowered to a typed high-level IR. Generic functions and classes are monomorphized — each instantiation like Stack<number> is compiled separately with its concrete types, so generics cost nothing at run time. Where types are known, method calls become static dispatch and object fields become direct, fixed-offset loads.
  4. Codegen (LLVM). The HIR is lowered to LLVM IR and run through LLVM's optimization pipeline — inlining, loop optimizations, vectorization — then emitted as machine code for the target.
  5. Link. The output is a normal platform executable: Mach-O on macOS, ELF on Linux, PE on Windows — plus mobile, watch, TV, and WebAssembly targets.

The LLVM side of this — why LLVM was chosen over Cranelift, how NaN-boxing represents dynamic values, what the optimizer does with typed IR — has its own deep dive: TypeScript on LLVM. Implementation details like NaN-boxing, static dispatch, and zero-cost abstractions are covered in the compiler internals.

What about dynamic code and npm?

TypeScript is still JavaScript underneath, and a native TypeScript compiler has to be honest about that. Perry's conformance against the official test262 suite is measured and published — as of v0.5.1146, String semantics are at 79% and Array at 72%, both climbing release over release. Pure TypeScript/JavaScript npm packages compile natively via perry.compilePackages: axios, zod v4, express, fastify, and hono compile and run today. Code that needs full engine semantics can opt into an embedded V8 fallback with --enable-js-runtime.

The full story is in Real npm packages and a conformance sweep.

How Perry relates to other “native TypeScript” efforts

Perry isn't the only project that has looked at TypeScript's type annotations and seen a compilation opportunity — but the approaches differ sharply. AssemblyScript compiles a strict TypeScript-like language to WebAssembly only: it is deliberately not JavaScript-compatible, and it doesn't produce OS executables or native UI. Meta's Static Hermes ahead-of-time compiles a typed JavaScript subset inside the Hermes engine, primarily for React Native — as of mid-2026 it remains a research project that must be built from source, and the Hermes V1 engine that actually shipped in React Native does not include the static features (full comparison).

Perry's bet is different on both axes: standard TypeScript as the input language, and ordinary platform executables — CLI, server, and GUI — as the output, installable today via Homebrew, APT, winget, or npm.

One compiler, ten targets

Because code generation goes through LLVM, one codebase compiles to macOS, iOS, iPadOS, Android, Linux, Windows, watchOS, tvOS, WebAssembly, and plain Web/JS — including cross-compiling Windows, macOS, and iOS binaries from a Linux machine. GUI apps use perry/ui, a declarative API over real platform widgets (AppKit, UIKit, GTK4, Win32, Android via JNI) — no webview involved.

How that stacks up against other approaches: Perry vs Bun, Deno, Electron, Tauri, React Native, and Static Hermes.

Try the compiler

Install Perry and compile your first native binary in under a minute.