Perry vs Bun
Bun is an all-in-one JavaScript/TypeScript runtime, bundler, package manager, and test runner that can also produce single-file executables by bundling its runtime with your code. Perry takes a different path: it compiles TypeScript directly to native machine code via LLVM — no JavaScript engine in the binary, no runtime, just a small native executable. Bun and Perry overlap on the TS-to-binary output but disagree about whether a JavaScript engine should be in that binary.
What is Bun?
Bun is a fast, all-in-one JavaScript and TypeScript toolkit built in Zig. It runs `.ts` source directly (no precompile step), uses JavaScriptCore as its JS engine, and includes a bundler, package manager, and test runner. `bun build --compile` bundles the Bun runtime together with your application into a single executable. Bun targets Linux, macOS, and Windows on x64 and arm64.
What is Perry?
Perry is a native TypeScript compiler written in Rust. It compiles TypeScript directly to native machine code via LLVM — no JavaScript engine, no runtime, no JIT. The output is a single binary (around 330 KB for a hello world; ~48 MB for a full stdlib app like a Fastify server). Perry targets 10 platforms including macOS, iOS, iPadOS, Android, Linux, Windows, watchOS, tvOS, WebAssembly, and the Web.
Side by side
| Feature | Perry | Bun |
|---|---|---|
| Output | Native machine code (LLVM) | Your code + Bun runtime bundled in one binary |
| JavaScript engine in binary | None by default; optional V8 with --enable-js-runtime (+~15 MB) | JavaScriptCore, always |
| Hello-world binary size | ~330 KB | ~50–100 MB (includes Bun runtime) |
| JIT | No (AOT compiled) | Yes (JavaScriptCore JIT) |
| Mobile targets (iOS, Android) | Yes — native UI via UIKit/JNI | No |
| Watch / TV targets | watchOS, tvOS, Wear OS | No |
| Native UI widgets | 25+ via AppKit, UIKit, GTK4, Win32, JNI | No (server/CLI focus) |
| npm ecosystem | Pure-TS/JS packages can compile natively; others via optional V8 | Full Node-compatible npm |
| Stability | Pre-1.0 (alpha) | Stable (1.x) |
| Built in | Rust | Zig |
Where Perry wins
- +Smaller binaries — a Perry hello world is ~330 KB; a Bun --compile hello world includes the Bun runtime and lands in the tens of megabytes.
- +No JavaScript engine cost. Perry-compiled binaries don't carry an interpreter or JIT — your TypeScript is the executable.
- +Mobile, watch, and TV. Perry compiles to iOS, iPadOS, Android, watchOS, tvOS, and WebAssembly. Bun is server/desktop only.
- +Native UI. Perry's perry/ui module compiles to real platform widgets (AppKit on macOS, UIKit on iOS, GTK4 on Linux, Win32 on Windows, JNI on Android). Bun has no UI story.
- +Faster on most compute microbenches measured under matched conditions on M1 Max (RUNS=11, v0.5.279, 2026-04-25): fibonacci 318 ms vs Bun 589 ms; object_create 1 ms vs 6 ms; nested_loops 18 ms vs 21 ms. See perry/benchmarks for the full table.
- +Faster on JSON validate-and-roundtrip in the dynamic-typing pack: Perry's lazy JSON tape lands at 75 ms median vs Bun's 259 ms on the same 10k-record workload.
Where Bun wins
- +Mature, stable runtime with 1.x releases. Perry is pre-1.0.
- +Faster on JSON parse-and-iterate (where every value is touched): Bun 254 ms vs Perry 466 ms median on the same workload — Perry's lazy tape can't shortcut when iteration is forced.
- +Full Node-compatible npm ecosystem out of the box. Perry runs a subset natively and falls back to optional embedded V8 for the rest.
- +Built-in test runner, bundler, and package manager. Perry is a compiler — adjacent tooling is separate.
- +JIT-warm performance can outpace AOT on iteration-heavy code with hot inner loops; Perry has no JIT.
- +Tied with Perry to within run-to-run noise on `loop_data_dependent` (232 ms vs 235 ms) — the genuinely-non-foldable f64 kernel where neither side's compiler can reorder. Source: perry/benchmarks RUNS=11.
When to choose Perry
Choose Perry when binary size matters (mobile distribution, embedded contexts, fast cold starts), when you want to ship to mobile/watch/TV from one TypeScript codebase, when you want native UI widgets, or when you don't want a JavaScript engine in your shipped artifact at all.
When to choose Bun
Choose Bun when you need a stable, mature runtime today, when full npm compatibility is non-negotiable, when you want a single tool for runtime + bundler + package manager + test runner, or when JIT-warm performance on long-running workloads matters more to you than cold-start size.
Verdict
Bun and Perry both let you ship a TypeScript program as a single binary, but they answer different questions. Bun's binary contains the Bun runtime and is optimized for backend/CLI workloads where JIT and full Node compatibility win. Perry's binary contains no JS engine and is optimized for size, cold-start, mobile, and native UI. If you're shipping a server, Bun is more proven today. If you're shipping a native app or care about binary size, Perry is built for that case.