A native TypeScript/JavaScript compiler written in Rust. Compiles TypeScript/JavaScript directly to executables using SWC and LLVM.
See the codeWrite TypeScript. Ship native. Everywhere.
Perry compiles the TypeScript you already write into real machine-code executables — for macOS, Windows, Linux, iOS, Android, watchOS, and TV. No Node.js to install. No Electron to bundle. No runtime at all. Just a binary. (The same codebase can also target the web, emitted as JavaScript or WebAssembly.)
Website · Documentation · Showcase · Examples
perry compile src/main.ts -o myapp
./myapp # a standalone native binary — ~330 KB for hello world
Millions of developers write TypeScript every day — but shipping it has always meant shipping a JavaScript engine: a Node install on every server, ~100 MB of embedded runtime per CLI, or a whole browser engine per desktop app. Perry removes the engine. SWC parses your code, LLVM compiles it to machine code, and you get what systems languages get: instant cold starts, tiny self-contained binaries, real threads — without leaving TypeScript.
| Perry | Node.js | Bun | Electron | |
|---|---|---|---|---|
| What you ship | One native binary, from ~330 KB | Your code + a Node install | One binary embedding the JS engine | App bundle with a browser engine |
| Execution | Ahead-of-time machine code | JIT | JIT | JIT |
| Cold start | Instant — no engine to boot, no warmup | Engine boot + warmup | Engine boot + warmup | Browser boot |
| Native UI (no WebView) | ✅ AppKit, UIKit, Android Views, Win32, GTK4 | — | — | Chromium |
| iOS · Android · watchOS · TV | ✅ from the same codebase | — | — | — |
| Multicore | Real OS threads, data-race-safe at compile time | worker_threads | workers | processes |
Table describes Perry's native targets. --target web / --target wasm emit JavaScript / WebAssembly that runs in the browser rather than as a native binary.
Ahead-of-time machine code means no engine boot and no JIT warmup — and on measured workloads, real multiples over the JS runtimes. Highlights from our open benchmark harnesses (Apple M1 Max, medians of repeated runs):
| Workload | Perry | Node.js | Bun | Rust |
|---|---|---|---|---|
| Image convolution (4K, 5×5 Gaussian) | 354 ms | 1,207 ms — 3.4× slower | 915 ms — 2.6× slower | 392 ms |
| Fibonacci (recursive calls) | 309 ms | 987 ms — 3.2× slower | 518 ms — 1.7× slower | 316 ms |
| JSON pipeline (100 records) | 39 ms | 144 ms — 3.7× slower | 51 ms — 1.3× slower | 34 ms |
| JSON pipeline (500k records, 108 MB) | 1,649 ms | 1,010 ms — 1.6× faster | 647 ms — 2.5× faster | 604 ms |
| Object allocation (1M objects) | 2 ms | 8 ms — 4× slower | 6 ms — 3× slower | <1 ms |
| Array write (10M elements) | 3 ms | 9 ms — 3× slower | 6 ms — 2× slower | 7 ms |
| Peak memory (JSON pipeline) | 3.5 MB | 36 MB — 10× more | 11 MB — 3× more | 1.2 MB |
Look at the Rust column again: on convolution, fibonacci, and the array-write loop, TypeScript compiled with Perry runs even with — or ahead of — Rust. And Electron isn't in the table because it doesn't compete here: it ships a whole browser engine per app, where a comparable Perry app is a single-digit-MB native binary.
Sources: convolution & JSON from the systems-language report
— pinned to 7beb3a50ca, the last revision whose artifact contains these values; the copy at HEAD was regenerated in #7641 on a host
where the harness clock was invalid and now reads 0.0 ms in every timing cell (see this PR). Re-pin to main once it is regenerated.
Fibonacci, object allocation & array write from the polyglot sweep (Perry default mode, no fast-math).
We publish everything, including the workloads where V8's JIT still beats us — no cherry-picked table can survive an open harness. Run it yourself: ./benchmarks/run_public_baseline.sh (methodology).
Generated from benchmarks/results/public-node-bun-v1.json at Perry commit b77aba63433b.
Lower wall-clock median is better; every row includes complete raw samples and passed correctness checks.
| Benchmark | Perry | Node.js | Bun | Result | What it tests |
|---|---|---|---|---|---|
| factorial | 93 ms | 95 ms | 95 ms | win vs both | Modular accumulation |
| method_calls | 35 ms | 11 ms | 8 ms | loss vs both | Class method dispatch |
| closure | 47 ms | 49 ms | 49 ms | win vs both | Closure creation and invocation |
| binary_trees | 13 ms | 6 ms | 6 ms | loss vs both | Tree allocation and traversal |
| string_concat | 6 ms | 31 ms | 5 ms | mixed | String append loop |
| prime_sieve | 6 ms | 5 ms | 5 ms | loss vs both | Sieve of Eratosthenes |
| mandelbrot | 25 ms | 24 ms | 29 ms | mixed | Complex-number iteration |
| matrix_multiply | 19 ms | 33 ms | 33 ms | win vs both | Matrix multiplication |
| json_roundtrip | 144 ms | 379 ms | 219 ms | win vs both | Parse and stringify ~1 MB JSON |
node:* modules — real implementations of fs, http/http2, net/tls, crypto, stream, child_process, worker_threads, fetch and the web globals, plus ~50 popular npm packages (Fastify, Express, mysql2, pg, ioredis, ws, bcrypt, jsonwebtoken…). Plain JavaScript compiles too.parallelMap, parallelFilter, and spawn on real OS threads — the compiler rejects shared mutable state, so data races don't compile.# Install (macOS · Linux · Windows)
npm install -g @perryts/perry # or: brew install perryts/perry/perry
# or: winget install PerryTS.Perry
# Create and run a project
perry init my-app && cd my-app
perry run .
npm packages and ES modules work as you'd expect:
import fastify from 'fastify';
const app = fastify();
app.get('/api/users', async () => [{ id: 1, name: 'Alice' }]);
app.listen({ port: 3000 }, () => console.log('Listening on :3000'));
perry compile src/main.ts -o api && ./api # one binary — no node_modules on the server
Same code, other platforms: --target ios, --target android, --target web… full list in the platforms guide. APT, Scoop, install script, and source builds are in the installation guide; run perry doctor to verify your setup.
Real products, shipping today:
| Project | What it is | Platforms |
|---|---|---|
| Bloom Engine | Native TypeScript game engine — Metal, DirectX 12, Vulkan, OpenGL | macOS, Windows, Linux, iOS, tvOS, Android |
| Mango | Native MongoDB GUI — ~7 MB binary, sub-second cold start | macOS, Windows, Linux, iOS, Android |
| Hone | AI-powered native code editor with terminal, Git, and LSP | macOS, Windows, Linux, iOS, Android, Web |
| dB Meter | Real-time sound level measurement at 60 fps | iOS, macOS, Android |
More in the showcase — built something with Perry? Open a PR and add it.
Everything else lives in the docs:
perry.toml, privacy & telemetryPerry is built in the open — come say hi:
Telemetry is opt-in: nothing leaves your machine unless you explicitly enable it in ~/.perry/config.toml, and PERRY_NO_TELEMETRY=1 (or CI=true) always wins. What can be sent is anonymous and redacted — never your source, paths, or project names. Inspect it any time with perry doctor, and see exactly what's in the payload in the privacy & telemetry docs.
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.
MIT
Rust
72.4%
TypeScript
10.2%
Python
7.9%
Assembly
5.7%
JavaScript
1.2%
LLVM
1.1%
Shell
1.0%
A native TypeScript/JavaScript compiler written in Rust. Compiles TypeScript/JavaScript directly to executables using SWC and LLVM.
See the codeWrite TypeScript. Ship native. Everywhere.
Perry compiles the TypeScript you already write into real machine-code executables — for macOS, Windows, Linux, iOS, Android, watchOS, and TV. No Node.js to install. No Electron to bundle. No runtime at all. Just a binary. (The same codebase can also target the web, emitted as JavaScript or WebAssembly.)
Website · Documentation · Showcase · Examples
perry compile src/main.ts -o myapp
./myapp # a standalone native binary — ~330 KB for hello world
Millions of developers write TypeScript every day — but shipping it has always meant shipping a JavaScript engine: a Node install on every server, ~100 MB of embedded runtime per CLI, or a whole browser engine per desktop app. Perry removes the engine. SWC parses your code, LLVM compiles it to machine code, and you get what systems languages get: instant cold starts, tiny self-contained binaries, real threads — without leaving TypeScript.
| Perry | Node.js | Bun | Electron | |
|---|---|---|---|---|
| What you ship | One native binary, from ~330 KB | Your code + a Node install | One binary embedding the JS engine | App bundle with a browser engine |
| Execution | Ahead-of-time machine code | JIT | JIT | JIT |
| Cold start | Instant — no engine to boot, no warmup | Engine boot + warmup | Engine boot + warmup | Browser boot |
| Native UI (no WebView) | ✅ AppKit, UIKit, Android Views, Win32, GTK4 | — | — | Chromium |
| iOS · Android · watchOS · TV | ✅ from the same codebase | — | — | — |
| Multicore | Real OS threads, data-race-safe at compile time | worker_threads | workers | processes |
Table describes Perry's native targets. --target web / --target wasm emit JavaScript / WebAssembly that runs in the browser rather than as a native binary.
Ahead-of-time machine code means no engine boot and no JIT warmup — and on measured workloads, real multiples over the JS runtimes. Highlights from our open benchmark harnesses (Apple M1 Max, medians of repeated runs):
| Workload | Perry | Node.js | Bun | Rust |
|---|---|---|---|---|
| Image convolution (4K, 5×5 Gaussian) | 354 ms | 1,207 ms — 3.4× slower | 915 ms — 2.6× slower | 392 ms |
| Fibonacci (recursive calls) | 309 ms | 987 ms — 3.2× slower | 518 ms — 1.7× slower | 316 ms |
| JSON pipeline (100 records) | 39 ms | 144 ms — 3.7× slower | 51 ms — 1.3× slower | 34 ms |
| JSON pipeline (500k records, 108 MB) | 1,649 ms | 1,010 ms — 1.6× faster | 647 ms — 2.5× faster | 604 ms |
| Object allocation (1M objects) | 2 ms | 8 ms — 4× slower | 6 ms — 3× slower | <1 ms |
| Array write (10M elements) | 3 ms | 9 ms — 3× slower | 6 ms — 2× slower | 7 ms |
| Peak memory (JSON pipeline) | 3.5 MB | 36 MB — 10× more | 11 MB — 3× more | 1.2 MB |
Look at the Rust column again: on convolution, fibonacci, and the array-write loop, TypeScript compiled with Perry runs even with — or ahead of — Rust. And Electron isn't in the table because it doesn't compete here: it ships a whole browser engine per app, where a comparable Perry app is a single-digit-MB native binary.
Sources: convolution & JSON from the systems-language report
— pinned to 7beb3a50ca, the last revision whose artifact contains these values; the copy at HEAD was regenerated in #7641 on a host
where the harness clock was invalid and now reads 0.0 ms in every timing cell (see this PR). Re-pin to main once it is regenerated.
Fibonacci, object allocation & array write from the polyglot sweep (Perry default mode, no fast-math).
We publish everything, including the workloads where V8's JIT still beats us — no cherry-picked table can survive an open harness. Run it yourself: ./benchmarks/run_public_baseline.sh (methodology).
Generated from benchmarks/results/public-node-bun-v1.json at Perry commit b77aba63433b.
Lower wall-clock median is better; every row includes complete raw samples and passed correctness checks.
| Benchmark | Perry | Node.js | Bun | Result | What it tests |
|---|---|---|---|---|---|
| factorial | 93 ms | 95 ms | 95 ms | win vs both | Modular accumulation |
| method_calls | 35 ms | 11 ms | 8 ms | loss vs both | Class method dispatch |
| closure | 47 ms | 49 ms | 49 ms | win vs both | Closure creation and invocation |
| binary_trees | 13 ms | 6 ms | 6 ms | loss vs both | Tree allocation and traversal |
| string_concat | 6 ms | 31 ms | 5 ms | mixed | String append loop |
| prime_sieve | 6 ms | 5 ms | 5 ms | loss vs both | Sieve of Eratosthenes |
| mandelbrot | 25 ms | 24 ms | 29 ms | mixed | Complex-number iteration |
| matrix_multiply | 19 ms | 33 ms | 33 ms | win vs both | Matrix multiplication |
| json_roundtrip | 144 ms | 379 ms | 219 ms | win vs both | Parse and stringify ~1 MB JSON |
node:* modules — real implementations of fs, http/http2, net/tls, crypto, stream, child_process, worker_threads, fetch and the web globals, plus ~50 popular npm packages (Fastify, Express, mysql2, pg, ioredis, ws, bcrypt, jsonwebtoken…). Plain JavaScript compiles too.parallelMap, parallelFilter, and spawn on real OS threads — the compiler rejects shared mutable state, so data races don't compile.# Install (macOS · Linux · Windows)
npm install -g @perryts/perry # or: brew install perryts/perry/perry
# or: winget install PerryTS.Perry
# Create and run a project
perry init my-app && cd my-app
perry run .
npm packages and ES modules work as you'd expect:
import fastify from 'fastify';
const app = fastify();
app.get('/api/users', async () => [{ id: 1, name: 'Alice' }]);
app.listen({ port: 3000 }, () => console.log('Listening on :3000'));
perry compile src/main.ts -o api && ./api # one binary — no node_modules on the server
Same code, other platforms: --target ios, --target android, --target web… full list in the platforms guide. APT, Scoop, install script, and source builds are in the installation guide; run perry doctor to verify your setup.
Real products, shipping today:
| Project | What it is | Platforms |
|---|---|---|
| Bloom Engine | Native TypeScript game engine — Metal, DirectX 12, Vulkan, OpenGL | macOS, Windows, Linux, iOS, tvOS, Android |
| Mango | Native MongoDB GUI — ~7 MB binary, sub-second cold start | macOS, Windows, Linux, iOS, Android |
| Hone | AI-powered native code editor with terminal, Git, and LSP | macOS, Windows, Linux, iOS, Android, Web |
| dB Meter | Real-time sound level measurement at 60 fps | iOS, macOS, Android |
More in the showcase — built something with Perry? Open a PR and add it.
Everything else lives in the docs:
perry.toml, privacy & telemetryPerry is built in the open — come say hi:
Telemetry is opt-in: nothing leaves your machine unless you explicitly enable it in ~/.perry/config.toml, and PERRY_NO_TELEMETRY=1 (or CI=true) always wins. What can be sent is anonymous and redacted — never your source, paths, or project names. Inspect it any time with perry doctor, and see exactly what's in the payload in the privacy & telemetry docs.
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.
MIT
Rust
72.4%
TypeScript
10.2%
Python
7.9%
Assembly
5.7%
JavaScript
1.2%
LLVM
1.1%
Shell
1.0%