Skip to main content

Introducing Script: JavaScript That Runs Like Rust

· 6 min read
Lucas Oliveira
Founder of Script

After years of starting, killing, restarting, and refining, I finally realised a dream: operating JavaScript at the low level. And I'm giving it to the world!

Script compiles JavaScript and TypeScript to native machine code, without garbage collection, featuring:

  • Rust-inspired ownership & borrow checking
  • Native compilation via LLVM & Cranelift
  • Full TypeScript syntax with type inference
  • Zero-overhead abstractions & standalone binaries

It compiles down to SSA-based IR and produces self-contained executables that run with native performance. As a result, we finally have a language that writes like JS but runs like Rust!

The Journey

I've been amazed by the performance of languages like Rust and Go, which I've been working on the backend for a while. And looking at JavaScript/TypeScript, I've always wanted to have the same performance, but I've never been able to achieve it.

First, I tried to create a hybrid server framework. I was studying on building a JavaScript library: a hybrid Rust+JavaScript web framework that combines Hyper's HTTP performance with JavaScript's flexibility.

So I developed a solution, and the initial benchmarks were... honest: 31,136 requests/second.

Not bad! I was able to beat Express.js by 55%. But I wanted more. I wanted to hit 88,000 req/sec, where fast JavaScript libraries, like Fastify, usually sit. But I was never able to achieve it.

Then I turned to the runtimes, primarily Node.js and then Bun. I studied how they work, and how Bun excels in performance and where to achieve it, and I realized that the best way to achieve it was to create a language that is a mix of Rust and JavaScript/TypeScript.

Philosophy

Script was born from four core principles:

  • Performance — I want to have the same performance as Rust and Go, but with the ease of use of JavaScript/TypeScript.
  • Memory Safety — I want to have the same memory safety as Rust, but with the ease of use of JavaScript/TypeScript.
  • Type Safety — I want to have the same type safety as Rust, but with the ease of use of JavaScript/TypeScript.
  • Ease of Use — I want to have the same ease of use of JavaScript/TypeScript, but with the performance of Rust and Go.

And then Script was born. It's still in its early stages—I call it a preview, and not yet production ready—but I've been able to achieve the performance I wanted, and the memory safety I wanted, and the type safety I wanted, and the ease of use I wanted.

What Makes Script Different

Native Compilation

Script doesn't use a virtual machine or JIT compilation. Instead, it compiles directly to native machine code using LLVM and Cranelift. This means:

  • Standalone binaries: No runtime dependencies
  • Fast startup: No warmup time, instant execution
  • Predictable performance: No JIT compilation overhead
  • Small binaries: Only what you need, nothing more

Rust-Inspired Memory Safety

Script brings Rust's ownership model to JavaScript:

// Ownership and borrowing prevent memory errors
let data = [1, 2, 3];
let borrowed = data; // Move ownership
// data is no longer accessible here

This eliminates entire classes of bugs:

  • Use-after-free
  • Double-free
  • Memory leaks
  • Data races

Full TypeScript Support

Script understands TypeScript syntax and type inference:

// Type inference works just like TypeScript
function add(a: number, b: number): number {
return a + b;
}

// Type checking at compile time
let result = add(5, 10); // ✓ Type safe
// let error = add("5", 10); // ✗ Compile error

Zero-Overhead Abstractions

Script's abstractions compile away to nothing:

// High-level code
const doubled = numbers.map((x) => x * 2);

// Compiles to efficient native code
// No function call overhead, no allocations

Current Status

Script has reached a major milestone: the compiler is now fully self-hosting and can generate native binaries!

Core Language Complete (Phases 0-4)

Phase 0: Runtime Kernel

  • NaN-boxed values for efficient memory representation
  • Unified heap allocator
  • FFI stubs for native backends

Phase 1: SSA IR System

  • Register-based SSA intermediate representation
  • Flow-sensitive type inference
  • Dead code elimination, constant folding, CSE
  • Borrow checking for memory safety

Phase 2: Native Backend

  • Cranelift JIT for fast development builds
  • LLVM AOT with ThinLTO and Full LTO
  • Multi-function JIT with tiered compilation
  • VM interpreter for debugging

Phase 3: Language Completion

  • Full TypeScript syntax support (types, interfaces, enums)
  • ES6 classes with inheritance and private fields
  • Async/await with Promise support
  • Try/catch/finally error handling
  • ES module system (import/export)

Phase 4: Self-Hosting CompilerCOMPLETE

  • Bootstrap compiler written in Script (~5,000 lines)
  • Modular compiler architecture (~3,500 lines)
  • Generates LLVM IR from Script source
  • Native binaries ~30x faster than VM
  • 113 tests passing

What You Can Do Today

# Self-hosted compiler generates LLVM IR
./script compiler/main.tscl llvm myapp.tscl

# Compile to native binary
clang myapp.tscl.ll -o myapp

# Run at native speed!
./myapp

Minimal Standard Library

Script core is intentionally minimal (like C without libc):

  • console.log, console.error
  • ByteStream for binary data
  • Basic fs operations (readFileSync, writeFileSync)
  • Everything else comes from the Rolls ecosystem (coming soon)

🚀 Next Phase: Rolls Ecosystem

  • Standard libraries (@rolls/http, @rolls/tls, @rolls/fs)
  • Package manager and build system (Unroll)
  • Language server and developer tools
  • Production-ready performance optimizations

Performance Benchmarks

Real-world performance with the self-hosted compiler:

Execution ModeDescriptionPerformance
VMBytecode interpreter (debugging)Baseline
Cranelift JITFast compilation for development~6x faster than VM
Native (LLVM IR)Self-hosted compiler output~30x faster than VM

Compilation Performance:

  • Arithmetic operations: 2.34 µs/iter (VM) → 0.39 µs/iter (JIT)
  • JIT compilation time: ~980 µs per function
  • Break-even point: ~500 iterations

Native Binary Examples:

  • Fibonacci(25): Matches Rust performance
  • Object/array operations: Full native speed
  • Function calls and recursion: Zero overhead

Note: Full benchmarks against Node.js and Bun will come with the Rolls ecosystem (HTTP server, etc.)

Getting Started

Try Script today:

# Clone the repository
git clone https://github.com/warpy-ai/script
cd script

# Build the compiler
cargo build --release

# Compile your first program
./target/release/script build hello.tscl -o hello
./hello

Write your code in TypeScript:

// hello.tscl
console.log("Hello, Script!");

And get a native binary that runs with Rust-like performance.

What's Next

With the core language complete and self-hosting achieved, the focus shifts to the ecosystem:

  • Rolls System Libraries: @rolls/http, @rolls/tls, @rolls/fs, @rolls/crypto, @rolls/async
  • Unroll Tooling: Package manager, build system, and project scaffolding
  • Developer Experience: Language server (LSP), debugger, profiler
  • Performance Tuning: Further LLVM optimizations, profile-guided optimization
  • Production Hardening: Comprehensive test coverage, real-world validation
  • Documentation: Complete API reference, tutorials, and examples

The self-hosted compiler opens the door to rapid iteration—now we can improve Script by writing Script!

Conclusion

Script represents a new approach to JavaScript: take the syntax and ease of use developers love, but give them the performance and safety of systems languages. It's still early, but the foundation is solid.

So give it a try, and let me know what you think. This is just the beginning.


Get Started:

Join the Community:

  • Report issues and suggest features
  • Contribute to the standard library
  • Share your Script projects
  • Help shape the future of Script