The TypeScript Runtime Problem
TypeScript has become the language of choice for millions of developers. The type safety, excellent tooling, and familiar JavaScript syntax make it ideal for everything from web apps to server-side code. But there's a catch.
To run TypeScript, you need Node.js. And Node.js comes with baggage:
- 80+ MB runtime: Every deployment includes the entire V8 JavaScript engine
- Cold start overhead: Lambda functions and containers spend hundreds of milliseconds just starting Node.js
- Memory consumption: V8's garbage collector and JIT compiler add significant memory overhead
- Distribution complexity: You can't just ship a binary โ users need Node.js installed
For many use cases, this overhead doesn't matter. But for CLI tools, serverless functions, edge computing, and embedded systems, every megabyte and millisecond counts.
What if you could compile TypeScript directly to machine code?
Introducing Perry
Perry is a native TypeScript compiler written in Rust. It compiles your TypeScript code directly to standalone executables โ no Node.js, no V8, no runtime required.
The results are striking:
- 2-5 MB binaries instead of 80 MB Node.js installations
- ~1ms startup time instead of hundreds of milliseconds
- 2.2x faster execution compared to Node.js
- Single-file distribution โ just ship the executable
Perry isn't just a toy or proof-of-concept. It supports real TypeScript features: generics, classes, async/await, closures, and more.
How Perry Works
Perry's architecture leverages battle-tested Rust components:
1. SWC for Parsing
Perry uses SWC (Speedy Web Compiler) to parse TypeScript. SWC is already widely adopted in tools like Next.js and Deno for its performance โ it's 20x faster than Babel. Written in Rust, it provides a fast, accurate TypeScript parser that handles all the language's syntax.
2. HIR Transformation
The parsed Abstract Syntax Tree (AST) is transformed into a High-Level Intermediate Representation (HIR). This representation is optimized for the next stage: code generation. During this phase, Perry performs type analysis and optimization passes.
3. Cranelift Code Generation
Cranelift generates the final machine code. It's the same code generator used by Wasmtime and other WebAssembly runtimes. Cranelift produces efficient native code for x86-64, ARM64, and other architectures.
4. NaN-Boxing for Union Types
TypeScript's union types (like string | number) pose a challenge for native compilation. Perry uses NaN-boxing โ a clever technique that encodes type information in the unused bits of 64-bit floats โ to efficiently represent dynamic types at runtime.
Performance Benchmarks
The numbers speak for themselves:
| Metric | Node.js | Perry | Improvement | |--------|---------|-------|-------------| | Binary Size | ~80 MB | 2-5 MB | 16-40x smaller | | Cold Start | 200-500ms | ~1ms | 200-500x faster | | Execution | baseline | 2.2x faster | 2.2x |
For CLI tools that run once and exit, the startup time difference is transformative. A Node.js CLI might spend 300ms just starting before executing a single line of your code. A Perry-compiled CLI is already done.
TypeScript Feature Support
Perry supports the TypeScript features developers actually use:
- Generics: Full generic type support
- Classes: Inheritance, static members, access modifiers
- Async/Await: Native async support without Promises overhead
- Closures: First-class function support
- Type Guards: Runtime type narrowing
- Enums: Both string and numeric enums
- Modules: ES module import/export
npm Ecosystem Compatibility
One of Perry's most impressive features is its native reimplementation of popular npm packages. Instead of running JavaScript through V8, these packages are reimplemented in Rust:
- Database: PostgreSQL, MongoDB, MySQL, SQLite
- Security: bcrypt, crypto, jwt
- HTTP: fetch, http client/server
- Utilities: Buffer, path, fs, os, child_process
- Data: JSON, Math, Date, RegExp
27+ packages are currently supported, with more being added. This means your existing TypeScript code that uses these libraries can compile to native code without modification.
Use Cases
CLI Tools
Perry is ideal for command-line tools. Instead of requiring users to install Node.js, you ship a single executable. The instant startup time makes the tool feel native โ because it is.
# Traditional Node.js CLI
npm install -g my-cli # Requires Node.js
my-cli --help # 200ms startup
# Perry-compiled CLI
./my-cli --help # <1ms startup
Serverless Functions
Cold starts kill serverless performance. A Lambda function that takes 500ms to cold start is burning money and frustrating users. Perry-compiled functions start in milliseconds, making serverless viable for latency-sensitive workloads.
Edge Computing
Edge runtimes like Cloudflare Workers have strict size limits. Perry's 2-5 MB binaries fit where 80 MB Node.js installations never could. Deploy TypeScript to the edge without compromising on language features.
Embedded Systems
IoT devices and embedded systems often have limited resources. Perry brings TypeScript's developer experience to environments where Node.js was never an option.
Getting Started
Perry is open source under MIT and Apache 2.0 licenses. Visit perryts.com to:
- Download the compiler for your platform
- Read the documentation for language support details
- Explore examples of Perry-compiled applications
- Contribute to the project on GitHub
The Future of TypeScript
Perry represents a fundamental shift in what's possible with TypeScript. By eliminating the runtime, it opens TypeScript to use cases that were previously impractical โ from embedded systems to high-frequency trading bots.
The project is actively developed and the ecosystem is growing. As more npm packages get native implementations and TypeScript feature coverage expands, Perry becomes increasingly viable for production use.
If you've ever wished TypeScript could compile to native code, Perry is making that dream a reality.
Perry is an open source project. Visit perryts.com to learn more.