Introduction
Perry is a native TypeScript compiler that compiles TypeScript source code directly to native executables. No JavaScript runtime, no JIT warmup, no V8 — your TypeScript compiles to a real binary.
// hello.ts
console.log("Hello from Perry!");
$ perry hello.ts -o hello
$ ./hello
Hello from Perry!
Why Perry?
- Native performance — Compiles to machine code via Cranelift. Integer-heavy code like Fibonacci runs 2x faster than Node.js.
- Small binaries — A hello world is ~300KB. Perry detects what runtime features you use and only links what’s needed.
- Native UI — Build desktop and mobile apps with declarative TypeScript that compiles to real AppKit, UIKit, GTK4, Win32, or DOM widgets.
- 6 platforms — macOS, iOS, Android, Windows, Linux, and Web from the same source code.
- Familiar ecosystem — Use npm packages like
fastify,mysql2,redis,bcrypt,lodash, and more — compiled natively. - Zero config — Point Perry at a
.tsfile and get a binary. Notsconfig.jsonrequired.
What Perry Compiles
Perry supports a practical subset of TypeScript:
- Variables, functions, classes, enums, interfaces
- Async/await, closures, generators
- Destructuring, spread, template literals
- Arrays, Maps, Sets, typed arrays
- Regular expressions, JSON, Promises
- Module imports/exports
- Generic type erasure
See Supported Features for the complete list.
Quick Example: Native App
import { App, Text, Button, VStack, State } from "perry/ui";
const count = State(0);
App("Counter", () =>
VStack([
Text(`Count: ${count.get()}`),
Button("Increment", () => count.set(count.get() + 1)),
])
);
$ perry counter.ts -o counter
$ ./counter # Opens a native macOS/Windows/Linux window
This produces a ~3MB native app with real platform widgets — no Electron, no WebView.
How It Works
TypeScript (.ts)
↓ Parse (SWC)
↓ Lower to HIR
↓ Transform (inline, closure conversion, async)
↓ Codegen (Cranelift)
↓ Link (system linker)
↓
Native Executable
Perry uses SWC for TypeScript parsing and Cranelift for native code generation. Types are erased at compile time (like tsc), and values are represented at runtime using NaN-boxing for efficient 64-bit tagged values.