MCPcopy Index your code
hub / github.com/PerryTS/perry

github.com/PerryTS/perry @v0.5.1220

Chat with this repo
repository ↗ · DeepWiki ↗ · release v0.5.1220 ↗ · + Follow
46,733 symbols 211,662 edges 7,011 files 7,452 documented · 16%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

Perry

One codebase. Every platform. Native performance.

Join the Perry Discord community

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.

Node.js compatibility

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.


Built with Perry

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

Screenshots

Mango — Native MongoDB GUI (source)

Mango — database explorer view Mango — document editor view

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

Hone — AI code editor built with Perry Bloom Jump — retro pixel platformer built with Bloom Engine

Have something you've built with Perry? Open a PR to add it here!


Sponsored by

Perry's development is backed by our sponsors. 🙏

Skelpo — premium sponsor

💎 Skelpo — Premium Sponsor

Want to support Perry and see your logo here? Get in touch via perryts.com.


Performance

As of v0.5.585, fast-math is opt-in. Perry's default mode emits no reassoc + contract per-instruction FMF flags, so f64 arithmetic is bit-exact with Node. --fast-math (CLI), PERRY_FAST_MATH=1 (env), or "perry": { "fastMath": true } in package.json re-enables the flags. See docs/src/cli/fast-math.md for 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.

vs Node.js and Bun

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).

Binary Size

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.


Installation

npm / npx (any platform)

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).

macOS (Homebrew)

brew install perryts/perry/perry

Windows (winget)

winget install PerryTS.Perry

Windows (Scoop)

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.

Debian / Ubuntu (APT)

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

Quick install (macOS / Linux)

curl -fsSL https://raw.githubusercontent.com/PerryTS/perry/main/packaging/install.sh | sh

From source

git clone https://github.com/PerryTS/perry.git
cd perry
cargo build --release
# Binary at: target/release/perry

Requirements

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.


Quick Start

```bash

Initialize a new project

perry init my-project cd my

Extension points exported contracts — how you extend this code

HirTypeFacts (Interface)
Read-only type facts needed by [`infer_expr_type`]. Keeping inference generic over this trait lets compiler phases reus [7 …
crates/perry-hir/src/analysis/value_types.rs
ToJsValue (Interface)
Trait for converting Redis results to perry-ffi `JsValue`. [5 implementers]
crates/perry-ext-ioredis/src/lib.rs
Printable (Interface)
(no doc) [11 implementers]
test-files/test_edge_interfaces.ts
Formatter (Interface)
(no doc) [12 implementers]
test-files/test_interface_dispatch_edge.ts
IGreeter (Interface)
(no doc) [10 implementers]
test-files/test_722_regress.ts
ContainerCommand (Interface)
(no doc) [5 implementers]
crates/perry-container-compose/src/commands/mod.rs
DiagnosticEmitter (Interface)
Trait for emitting diagnostics in various formats. [3 implementers]
crates/perry-diagnostics/src/emitter.rs
Matcher (Interface)
(no doc) [4 implementers]
test-files/test_628_dyn.ts

Core symbols most depended-on inside this repo

log
called by 22907
test-files/test_edge_interfaces.ts
get
called by 5468
types/perry/ui/index.d.ts
clone
called by 5361
test-files/test_gap_4461_class_expr_var_value.ts
with
called by 5015
crates/perry-runtime/src/child_process/v8_serde.rs
push
called by 4805
crates/perry-hir/src/lower/locals.rs
map
called by 4310
test-files/test_edge_generics.ts
as_ptr
called by 4012
crates/perry-runtime/src/node_submodules/mod.rs
iter
called by 3925
crates/perry-codegen/src/strings.rs

Shape

Function 38,328
Method 3,896
Class 3,854
Enum 499
Interface 150
Struct 6

Languages

Rust81%
TypeScript17%
Python1%
Kotlin1%
C++1%
Go1%

Modules by API surface

crates/perry-ui-android/src/stdlib_stubs.rs407 symbols
crates/perry-codegen-js/src/web_runtime.js393 symbols
crates/perry-ui-watchos/src/lib.rs373 symbols
crates/perry-codegen-wasm/src/wasm_runtime.js333 symbols
crates/perry-codegen/tests/native_proof_regressions.rs301 symbols
docs/api/perry.d.ts262 symbols
crates/perry-ui-android/template/app/src/main/java/com/perry/app/PerryBridge.kt158 symbols
crates/perry-runtime/src/node_vm.rs156 symbols
crates/perry-runtime/src/node_stream_readwrite.rs149 symbols
test-files/test_issue_945_scalar_method_guards.ts133 symbols
crates/perry-runtime/src/node_stream.rs133 symbols
crates/perry-ui-ios/src/ffi/widgets_basic.rs132 symbols

Datastores touched

(mysql)Database · 1 repos
(mongodb)Database · 1 repos
appDatabase · 1 repos
dbDatabase · 1 repos
mydbDatabase · 1 repos
postgresDatabase · 1 repos
mydbDatabase · 1 repos

For agents

$ claude mcp add perry \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact