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.
// demonstrates: the one-liner hello shown on the docs landing page
// docs: docs/src/introduction.md
// platforms: macos, linux, windows
// targets: wasm, web, android
console.log("Hello from Perry!")
$ perry hello.ts -o hello
$ ./hello
Hello from Perry!
Why Perry?
- Native performance — Compiles to machine code via LLVM. Integer-heavy code like Fibonacci runs 2x faster than Node.js.
- Real multi-threading —
parallelMapandspawngive you actual OS threads with compile-time safety. No isolates, no message passing overhead. Something no JS runtime can do. - 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.
- Terminal UI — Build interactive CLIs with ink-shape React hooks (
useState,useEffect,useApp) on a native cell-grid renderer. No Node, no reconciler — just a single static binary. - 7 targets — macOS, iOS, Android, Windows, Linux, Web, and WebAssembly 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
// demonstrates: minimal stateful UI — label + increment button
// docs: docs/src/ui/state.md
// platforms: macos, linux, windows
// targets: ios-simulator, visionos-simulator, tvos-simulator, watchos-simulator, android, web, wasm
import { App, VStack, Text, Button, State } from "perry/ui"
const count = State(0)
App({
title: "Counter",
width: 400,
height: 300,
body: VStack(16, [
Text(`Count: ${count.value}`),
Button("Increment", () => count.set(count.value + 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 (LLVM)
↓ Link (system linker)
↓
Native Executable
Perry uses SWC for TypeScript parsing and LLVM 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.