Perry vs Bun
Bun ist eine All-in-One-JavaScript/TypeScript-Runtime, ein Bundler, Paketmanager und Test-Runner, der zudem Single-File-Executables erzeugen kann, indem er seine Runtime mit deinem Code bündelt. Perry geht einen anderen Weg: Es kompiliert TypeScript direkt über LLVM zu nativem Maschinencode — keine JavaScript-Engine im Binary, keine Runtime, einfach ein kleines natives Executable. Bun und Perry überschneiden sich beim TS-zu-Binary-Output, sind sich aber uneinig darüber, ob eine JavaScript-Engine in diesem Binary stecken sollte.
Was ist Bun?
Bun ist ein schnelles, in Zig gebautes All-in-One-Toolkit für JavaScript und TypeScript. Es führt `.ts`-Quellcode direkt aus (kein Vorab-Kompilierungsschritt), nutzt JavaScriptCore als JS-Engine und enthält einen Bundler, Paketmanager und Test-Runner. `bun build --compile` bündelt die Bun-Runtime zusammen mit deiner Anwendung in ein einzelnes Executable. Bun unterstützt Linux, macOS und Windows auf x64 und arm64.
Was ist Perry?
Perry ist ein nativer TypeScript-Compiler, geschrieben in Rust. Er kompiliert TypeScript direkt über LLVM zu nativem Maschinencode — keine JavaScript-Engine, keine Runtime, kein JIT. Das Ergebnis ist ein einzelnes Binary (rund 330 KB für ein Hello World; ~48 MB für eine komplette Stdlib-App wie einen Fastify-Server). Perry zielt auf 10 Plattformen, darunter macOS, iOS, iPadOS, Android, Linux, Windows, watchOS, tvOS, WebAssembly und das Web.
Direktvergleich
| Feature | Perry | Bun |
|---|---|---|
| Output | Nativer Maschinencode (LLVM) | Dein Code + Bun-Runtime, gebündelt in einem Binary |
| JavaScript-Engine im Binary | Standardmäßig keine; optional V8 mit --enable-js-runtime (+~15 MB) | JavaScriptCore, immer |
| Hello-World-Binary-Größe | ~330 KB | ~50–100 MB (inklusive Bun-Runtime) |
| JIT | Nein (AOT-kompiliert) | Ja (JavaScriptCore JIT) |
| Mobile-Targets (iOS, Android) | Ja — native UI über UIKit/JNI | Nein |
| Watch- / TV-Targets | watchOS, tvOS, Wear OS | Nein |
| Native UI-Widgets | 25+ über AppKit, UIKit, GTK4, Win32, JNI | Nein (Server/CLI-Fokus) |
| npm-Ökosystem | Reine TS-/JS-Pakete können nativ kompilieren; andere über optionales V8 | Volle Node-kompatible npm-Unterstützung |
| Stabilität | Pre-1.0 (Alpha) | Stabil (1.x) |
| Gebaut in | Rust | Zig |
Wo Perry gewinnt
- +Kleinere Binaries — ein Perry-Hello-World ist ~330 KB; ein Bun-`--compile`-Hello-World enthält die Bun-Runtime und liegt im zweistelligen Megabyte-Bereich.
- +Keine JavaScript-Engine-Kosten. Perry-kompilierte Binaries tragen keinen Interpreter und kein JIT mit sich — dein TypeScript ist das Executable.
- +Mobile, Watch und TV. Perry kompiliert für iOS, iPadOS, Android, watchOS, tvOS und WebAssembly. Bun läuft nur auf Server und Desktop.
- +Native UI. Perrys perry/ui-Modul kompiliert zu echten Plattform-Widgets (AppKit auf macOS, UIKit auf iOS, GTK4 auf Linux, Win32 auf Windows, JNI auf Android). Bun hat keine UI-Story.
- +Schneller in den meisten Compute-Mikrobenchmarks unter abgestimmten Bedingungen auf 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. Siehe perry/benchmarks für die vollständige Tabelle.
- +Schneller bei JSON Validate-and-Roundtrip im Pack der dynamisch typisierten Runtimes: Perrys Lazy-JSON-Tape liefert 75 ms Median gegenüber Buns 259 ms beim gleichen 10k-Datensatz-Workload.
Wo Bun gewinnt
- +Reife, stabile Runtime mit 1.x-Releases. Perry ist Pre-1.0.
- +Schneller bei JSON Parse-and-Iterate (wo jeder Wert berührt wird): Bun 254 ms vs Perry 466 ms Median beim gleichen Workload — Perrys Lazy-Tape kann nicht abkürzen, wenn Iteration erzwungen wird.
- +Volle Node-kompatible npm-Unterstützung von Haus aus. Perry führt einen Teil nativ aus und greift für den Rest auf das optional eingebettete V8 zurück.
- +Eingebauter Test-Runner, Bundler und Paketmanager. Perry ist ein Compiler — angrenzendes Tooling ist separat.
- +JIT-warme Performance kann AOT bei iterationslastigem Code mit heißen inneren Schleifen überholen; Perry hat kein JIT.
- +Gleichauf mit Perry innerhalb des Run-zu-Run-Rauschens bei `loop_data_dependent` (232 ms vs 235 ms) — der echt nicht-faltbare f64-Kernel, bei dem keiner der Compiler umordnen kann. Quelle: perry/benchmarks RUNS=11.
Wann Perry wählen
Wähle Perry, wenn die Binary-Größe wichtig ist (mobile Distribution, eingebettete Kontexte, schnelle Cold Starts), wenn du aus einer TypeScript-Codebasis für Mobile/Watch/TV ausliefern willst, wenn du native UI-Widgets brauchst oder wenn du gar keine JavaScript-Engine in deinem ausgelieferten Artefakt haben willst.
Wann Bun wählen
Wähle Bun, wenn du heute eine stabile, ausgereifte Runtime brauchst, wenn volle npm-Kompatibilität nicht verhandelbar ist, wenn du ein einziges Tool für Runtime + Bundler + Paketmanager + Test-Runner möchtest, oder wenn dir JIT-warme Performance auf langlaufenden Workloads wichtiger ist als die Cold-Start-Größe.
Fazit
Bun und Perry erlauben beide, ein TypeScript-Programm als ein einzelnes Binary auszuliefern, beantworten aber unterschiedliche Fragen. Buns Binary enthält die Bun-Runtime und ist auf Backend/CLI-Workloads optimiert, bei denen JIT und volle Node-Kompatibilität gewinnen. Perrys Binary enthält keine JS-Engine und ist auf Größe, Cold Start, Mobile und native UI optimiert. Wenn du einen Server ausliefern willst, ist Bun heute erprobter. Wenn du eine native App ausliefern willst oder dir die Binary-Größe wichtig ist, ist Perry für genau diesen Fall gebaut.