One codebase. Every platform. Native performance.
Perry is a native TypeScript compiler written in Rust. It takes your TypeScript and compiles it straight to native executables — no Node.js, no Electron, no browser engine. Just fast, small binaries that run anywhere.
Current Version: 0.5.1164 | Website | Documentation | Showcase
Community: Join the Perry Discord
perry compile src/main.ts -o myapp
./myapp # that's it — a standalone native binary
Perry uses SWC for TypeScript parsing and LLVM for native code generation. The output is a single binary with no runtime dependencies.
Perry targets close behavioral parity with Node.js. Against Node's own test suite
(node v26.3.0, 53 node:* modules), Perry's native runtime passes ~97%
(2792 / 2863 cases), and overall Node/TypeScript compatibility sits around 95%.
Real implementations — not stubs — cover fs, http/https/http2, net/tls,
dns/dgram, crypto, stream (+ stream/web), events, child_process,
cluster, worker_threads, zlib, process, async_hooks /
AsyncLocalStorage, Atomics / SharedArrayBuffer (cross-thread), the WHATWG
web globals (fetch, URL, streams, structuredClone, WebCrypto, …), and ~50
popular npm packages. The remaining gap is a long tail of edge-case options and a
few categorical items (lookbehind regex, some console formatting). See
docs/runtime-parity-gaps.md.
Perry also compiles .js / .cjs / .mjs / .jsx source directly (parsed as
JavaScript, lowered through the same native pipeline as TypeScript) — no
TypeScript annotations required. There are no guarantees for every dynamic JS
pattern, but plain JavaScript projects compile and run in most cases.
People are building real apps with Perry today. Here are some highlights:
| Project | What it is | Platforms |
|---|---|---|
| Bloom Engine | Native TypeScript game engine — Metal, DirectX 12, Vulkan, OpenGL. Write games in TS, ship native. | macOS, Windows, Linux, iOS, tvOS, Android |
| Bloom Jump | Free retro pixel platformer — five hand-crafted levels, 60 FPS, original chiptune soundtrack. Built entirely with Bloom Engine. | iOS, iPadOS, macOS, tvOS, visionOS, watchOS, Android |
| Mango | Native MongoDB GUI. ~7 MB binary, <100 MB RAM, sub-second cold start. | macOS, Windows, Linux, iOS, Android |
| Hone | AI-powered native code editor with built-in terminal, Git, and LSP. | macOS, Windows, Linux, iOS, Android, Web |
| Pry | Fast, native JSON viewer with tree navigation and search. | macOS, iOS, Android |
| dB Meter | Real-time sound level measurement with 60fps updates and per-device calibration. | iOS, macOS, Android |
Mango — Native MongoDB GUI (source)

Hone — AI-powered native code editor (hone.codes) · Bloom Jump — retro pixel platformer (showcase)

Have something you've built with Perry? Open a PR to add it here!
Perry's development is backed by our sponsors. 🙏
💎 Skelpo — Premium Sponsor
Want to support Perry and see your logo here? Get in touch via perryts.com.
As of v0.5.585, fast-math is opt-in. Perry's default mode emits no
reassoc + contractper-instruction FMF flags, so f64 arithmetic is bit-exact with Node.--fast-math(CLI),PERRY_FAST_MATH=1(env), or"perry": { "fastMath": true }inpackage.jsonre-enables the flags. Seedocs/src/cli/fast-math.mdfor the discussion of when it does and doesn't matter. The numbers below are Perry's default mode unless noted.
Numbers below are from a 2026-05-14 sweep on macOS ARM64 (M1 Max, RUNS=11 medians, taskpolicy -t 0 -l 0) at Perry v0.5.908 on an otherwise-idle machine. All languages re-measured together this run. Source + methodology in benchmarks/polyglot/.
| Benchmark | Perry | Rust | C++ | Go | Swift | Java | Node | Bun | What it tests |
|---|---|---|---|---|---|---|---|---|---|
| fibonacci | 309 | 316 | 309 | 446 | 401 | 278 | 987 | 518 | Recursive function calls (i64 specialization) |
| loop_data_dependent | 225 | 226 | 129 | 128 | 225 | 226 | 226 | 230 | Multiplicative carry through sum (genuinely-non-foldable f64) |
| object_create | 2 | 0 | 0 | 0 | 0 | 5 | 8 | 6 | Object allocation (1M objects, scalar replacement) |
| nested_loops | 18 | 8 | 8 | 10 | 8 | 10 | 17 | 20 | Nested array access (cache-bound) |
| array_read | 11 | 9 | 9 | 10 | 9 | 11 | 14 | 16 | Sequential read (10M elements) |
| array_write | 3 | 7 | 2 | 9 | 2 | 6 | 9 | 6 | Sequential write (10M elements) |
Default Perry runs in the same neighborhood as Rust default -O, C++ -O3, and Swift -O on every row — competitive on integer recursion (fibonacci 309 vs Rust 316 / C++ 309), within a tick of native on object allocation thanks to scalar replacement (object_create), within a few ms on cache-bound work (nested_loops, array_read/array_write), and matching the no-contract compiled pack on genuinely-non-foldable f64 (loop_data_dependent 225 vs Rust 226 / Bun 230 / Node 226). Apple Clang -O3 and Go default win the loop_data_dependent row at 128-129 by fusing sum * a + b into a single FMADDD instruction (FMA contraction is -ffp-contract=fast — a separate knob --fast-math deliberately doesn't toggle). Python column omitted to keep the table readable; full numbers in benchmarks/polyglot/RESULTS.md.
We deliberately don't lead with the trivially-foldable accumulator microbenchmarks (loop_overhead / math_intensive / accumulate) that Perry posted big numbers on through v0.5.584. Those are flag-aggressiveness probes — they measure whether each compiler applied reassoc + autovectorize to a sum += 1.0-shaped loop, not how fast the resulting loop computes under load. Perry default sits in the no-flags pack (97 / 51 / 97 ms in this sweep) on all three; --fast-math recovers 12 / 14 / 34 ms. C++ -O3 -ffast-math matches Perry --fast-math to the millisecond on the same kernels — same LLVM pipeline, one flag. The full breakdown is in benchmarks/README.md and polyglot/RESULTS_OPT.md.
Perry's broader benchmark suite covers workloads outside the polyglot set — closures, classes, JSON, prime sieve, etc. Numbers below from the 2026-05-14 v0.5.908 sweep via benchmarks/suite/run_benchmarks.sh (single-run-per-cell, not RUNS=11 medians — see benchmarks/polyglot/ for the rigorous multi-run methodology).
| Benchmark | Perry (v0.5.908) | Node.js | Bun | What it tests |
|---|---|---|---|---|
| factorial | 107ms | 591ms | 97ms | Modular accumulation (integer fast path) |
| method_calls | 9ms | 11ms | 9ms | Class method dispatch (10M calls) |
| closure | 50ms | 304ms | 51ms | Closure creation + invocation (10M calls) |
| binary_trees | 2ms | 10ms | 7ms | Tree allocation + traversal (1M nodes, scalar replacement) |
| string_concat | 0ms | 3ms | 1ms | 100K string appends |
| prime_sieve | 3ms | 8ms | 7ms | Sieve of Eratosthenes |
| mandelbrot | 28ms | 25ms | 29ms | Complex f64 iteration (800x800) |
| matrix_multiply | 28ms | 34ms | 34ms | 256x256 matrix multiply |
| json_roundtrip (lazy tape, gen-gc) | 83ms | 377ms | 249ms | 50× JSON.parse + JSON.stringify on a ~1MB, 10K-item blob |
closure and factorial are still slower than the older v0.5.173 baseline (10 → 50 ms, 31 → 107 ms). The v0.5.585 fast-math opt-in flip accounts for factorial (integer modulo plus an FP-tail reduction that the old default-on fast-math collapsed); closure regression is tracked as a follow-up. method_calls is back at baseline this sweep (9 ms) — yesterday's 25 ms reading was single-run noise from concurrent CPU load. The wins on binary_trees / string_concat / prime_sieve / mandelbrot / matrix_multiply against Node/Bun hold steady. Single-run cells are noisier than RUNS=11 medians; the lower-noise multi-run polyglot table above remains the canonical comparison.
Perry compiles to native machine code via LLVM — no JIT warmup, no interpreter overhead. Key optimizations that apply in both modes: scalar replacement of non-escaping objects (escape analysis eliminates heap allocation entirely — object fields become registers), inline bump allocator for objects that do escape, i32 loop counters for bounded array access, integer-modulo fast path (fptosi → srem → sitofp instead of fmod), elimination of redundant js_number_coerce calls on numeric function returns, and i64 specialization for pure numeric recursive functions.
Run benchmarks yourself: cd benchmarks/suite && ./run_benchmarks.sh (requires node, cargo; optional: bun, shermes).
Perry produces small, self-contained binaries with no external dependencies at run time:
| Program | Binary Size |
|---|---|
console.log("Hello, world!") |
~330KB |
hello world + fs / path / process imports |
~380KB |
| full stdlib app (fastify, mysql2, etc.) | ~48MB |
with --enable-js-runtime (V8 embedded) |
+~15MB |
Perry automatically detects which parts of the runtime your program uses and only links what's needed.
Perry ships as a prebuilt-binary npm package — the fastest way to try it, and the only install path that works on all seven supported platforms (macOS arm64/x64, Linux x64/arm64 glibc + musl, Windows x64) with one command:
# Project-local (recommended — pins Perry's version alongside your deps)
npm install @perryts/perry
npx perry compile src/main.ts -o myapp && ./myapp
# Global
npm install -g @perryts/perry
perry compile src/main.ts -o myapp
# Zero-install, one-shot
npx -y @perryts/perry compile src/main.ts -o myapp
@perryts/perry is a thin launcher; npm automatically picks the matching prebuilt via optionalDependencies (@perryts/perry-darwin-arm64, @perryts/perry-linux-x64-musl, etc.) based on your os / cpu / libc. Requires Node.js ≥ 16 and a system C toolchain for linking (same as any Perry install — see Requirements).
brew install perryts/perry/perry
winget install PerryTS.Perry
scoop bucket add perry-ts https://github.com/PerryTS/perry
scoop install perry-ts/perry
The Scoop manifest declares main/llvm as a dependency, so scoop install automatically pulls the official MSVC-default LLVM toolchain Perry needs for Windows-native object emission. Verify with perry doctor after install.
curl -fsSL https://perryts.github.io/perry-apt/perry.gpg.pub | sudo gpg --dearmor -o /usr/share/keyrings/perry.gpg
echo "deb [signed-by=/usr/share/keyrings/perry.gpg] https://perryts.github.io/perry-apt stable main" | sudo tee /etc/apt/sources.list.d/perry.list
sudo apt update && sudo apt install perry
curl -fsSL https://raw.githubusercontent.com/PerryTS/perry/main/packaging/install.sh | sh
git clone https://github.com/PerryTS/perry.git
cd perry
cargo build --release
# Binary at: target/release/perry
Perry requires a C linker to link compiled executables:
- macOS: Xcode Command Line Tools (xcode-select --install)
- Linux: GCC or Clang (see below for your distro)
- Windows: MSVC (Visual Studio Build Tools)
Linux linker by distro:
# Debian / Ubuntu / Pop!_OS / Mint
sudo apt install build-essential
# Arch / Manjaro / CachyOS / EndeavourOS
sudo pacman -S base-devel gcc
# Fedora / RHEL / CentOS Stream
sudo dnf install gcc gcc-c++ glibc-devel
# openSUSE
sudo zypper install -t pattern devel_basis
# Alpine / musl-based
sudo apk add build-base
# Void Linux
sudo xbps-install -S base-devel
Run perry doctor to verify your environment.
```bash
perry init my-project cd my
$ claude mcp add perry \
-- python -m otcore.mcp_server <graph>