Tiered JIT, ownership memory, and no GC — the architecture doc explains how. Read it →
alpha Haxe 4.x, natively →

Instant Haxe.
Native performance.

A Haxe compiler with a tiered JIT, Cranelift and LLVM backends, and no garbage collector.

Get started GitHub
Particles.hx
// hot loop promoted to LLVM after ~1k calls
class Particles {
  static function update(p:Array<Particle>, dt:Float) {
    for (i in 0...p.length) {
      var q = p[i];
      q.vy += 9.81 * dt;
      q.x += q.vx * dt;
      q.y += q.vy * dt;
    }
  }

  static function main() {
    var world = Particle.spawn(100000);
    for (frame in 0...1200) update(world, 1/60);
  }
}
Try it in the playground → edit, compile and run in the browser
coming soon
$ rayzor run Particles.hx
tier 0 · interp first output at 38ms
profile update() hot — 1,024 calls
tier 1 · cranelift compiled in 4.2ms
tier 3 · llvm compiled in 61ms, -O2
steady state 3.1× interpreter throughput
<50ms
to first output — the interpreter runs before anything is compiled
Tiered
interpreter → Cranelift → LLVM, promoted per function on profile data
Hot reload
swap a changed module into a running program without restarting it
0 GC
drops inserted at compile time from last-use and escape analysis
3 backends
Cranelift and LLVM for native, plus WebAssembly — one optimized SSA behind all three
Targets

Desktop, server, and the browser.

One codebase, one runtime, four places to put it. WebAssembly is not an afterthought here — it goes through the same optimized MIR as the native backends and ships as a core module, a WASI P2 component, or a browser bundle.

Linux
x86_64 · aarch64

Native binaries through LLVM, or the Cranelift JIT while you work. Threads, sockets and the full runtime, plus NUMA-aware worker pinning on servers.

rayzor aot main.hx -o app
macOS
aarch64 · x86_64

The same native path on Apple silicon and Intel, with a worker pool that adapts to the machine instead of fighting it.

rayzor aot main.hx -o app
Windows
x86_64 · MSVC

Native binaries through the MSVC toolchain, with the same tiered JIT and the same runtime you develop against elsewhere.

rayzor aot main.hx -o app.exe
WebAssembly
first-class target

Core modules, WASI P2 components, and a browser harness — the same MIR through the same optimization passes as the native backends.

rayzor build --target wasm --browser
Cross-compile --target <triple> --sysroot <dir> --linker <path> --target wasm-wasi
Policy

Haxe is a systems language.
We compile it like one.

Haxe already has the type system, the macros and the ergonomics. What it hasn't had is a compiler that goes straight to machine code, frees memory without a collector, and optimizes once for every backend. That's what Rayzor does — with the Haxe you already write.

01 Correctness first

An optimization ships after it's proven correct. Drop insertion and inline are guarantees, not hints, so they run at every level — including -O0.

02 No garbage collector

The compiler works out when to free things. No pauses in the middle of a frame, and you can annotate one class at a time.

03 Analysis is shared

Dominance, loop structure and escape info are computed once and reused by every pass that needs them.

04 Same source, same binary

MIR collections are ordered on purpose, so codegen is reproducible build after build.

05 Don't redo work

Parsing, type checking, module caching and bundling all skip what hasn't changed. Caching is on by default.

06 Optimize once

Every backend reads the same SSA, so a pass written for the JIT also speeds up your native binary and your wasm module.

Not a goal

Transpilation. The official Haxe compiler is very good at emitting JavaScript, Python and PHP — Rayzor has no such target and won't. Use the official compiler when you ship source, Rayzor when you ship machine code.

Memory

No collector. No pauses.

The compiler decides when every value is freed, from last-use and escape analysis. You reach for annotations only where aliasing actually matters.

@:move class Texture {
  public var pixels:Bytes;
}

@:arc class Atlas {
  public var pages:Array<Texture>;
}

@:safety(strict)
class Main {
  static function main() {
    var t = new Texture();
    upload(t);
    // upload(t);  ← error: use after move
  }
}
@:moveUnique ownership

Move semantics, no aliasing. Use-after-move is a hard error, caught before you run.

@:arcShared across threads

Atomic reference counting, for state that genuinely needs more than one owner.

@:deriveChecked concurrency

Send and Sync markers, validated against Thread, Channel, Mutex and Arc.

@:safetyAdopt it incrementally

Strict mode requires every class to be annotated; non-strict wraps the rest in Rc — so ownership is never a rewrite you do first.

Benchmarks

One pipeline,
optimized once.

Same Haxe source on every target. Rayzor is faster than HashLink outright, faster than the JVM without paying its startup, and faster than hxcpp on floating-point work — and it gets there in tens of milliseconds of compile time, not hundreds.

That compile column is the part you feel all day. No C++ toolchain to set up, no JVM to warm, no separate build step before you can run — rayzor run starts executing while the optimizer is still working. And it's a cold number: the BLADE cache keeps every unchanged module compiled, so the second build compilation is instant.

3 measured iterations, mean reported. INTEL(R) XEON(R) PLATINUM 8573C, linux, x86_64, 2026-08-24.

Full results, regenerated by CI ↗
Rayzor · tiered 524ms1.17×
Rayzor · LLVM 448msfastest
Rayzor · Cranelift 510ms1.14×
hxcpp 490ms1.09×
Haxe/JVM 701ms1.57×
HashLink/C 928ms2.07×
HashLink 1.93s ▸4.32×
lower is better

execution only, mean of 10 measured runs · milliseconds, smaller is better
axis clips at 4× the fastest — ▸ marks a bar past the edge, real value labeled

SIMD

Vectors are a type,
not an intrinsic.

The SIMD* family is first-class Haxe — 128- and 256-bit, float and integer lanes — with tuple and array literals, real operator overloads, and a full math surface: dot, normalize, magnitude, lerp. It lowers to NEON, SSE2 or WASM SIMD128, with a scalar fallback where none exists.

The interpreter handles vector types, and functions that use SIMD are promoted on first call — so vector work runs compiled from the start without giving up instant startup.

How it lowers ↗
Vectors.hx
import rayzor.SIMD4f;

var a:SIMD4f = (1.0, 2.0, 3.0, 4.0);
var b = SIMD4f.splat(2.0);
var c = a * b + a;
var d = a.dot(b);
var n = a.normalize();
Get started

Running in a minute.

Point Rayzor at a .hx file, or hand it the build.hxml you already have.

runtiered JIT, cache on by default
aotwhole program through LLVM to a native binary
bundleone portable .rzb that skips compilation
buildnative, wasm or wasm-wasi from a manifest
$ curl -fsSL https://rayzor.tech/install.sh | sh
Installs to ~/.rayzor/bin. The download carries its own LLVM, so nothing else needs installing.
then
$ rayzor init --name my-app
$ rayzor run src/Main.hx
Hello, Rayzor
tier 0 → 1 → 3 · 41ms total
Who it's for

Where a native Haxe pays off.

Servers

Long-running processes where a collector pause is a latency spike you can't explain to anyone. Memory is freed by analysis, so tail latency is a property of your code, not the runtime's mood.

The server preset optimizes aggressively for processes that stay up
Real OS threads with Channel, Select, Mutex and Arc — not a green-thread emulation
Ship one native binary, or one .rzb that skips compilation at startup
rayzor aot --preset server Channel<T> 0 GC pauses
Game development

Frame budgets don't survive a stop-the-world pause. Ownership annotations put allocation lifetimes where you can see them, and the JIT means iteration doesn't wait on a full build.

@:move and @:arc where aliasing matters; everything else stays ordinary Haxe
SIMD4f with operator overloads for transforms, physics and batch math
@:shader classes compile straight to WGSL — write shaders in Haxe, not a second language
@:cstruct gives flat, headerless layouts for C ABI compatibility — bind only what you must
SIMD4f @:shader → WGSL @:move @:cstruct
High-performance computing

The parts that usually push people out of Haxe and into C: vector types, thread pools that don't re-spawn, and control over which core does what.

128- and 256-bit vectors with widening dot-accumulate for quantized kernels
SpinPool keeps workers alive and chunk-steals — dispatch costs a few atomic stores
WorkerPool pins one worker per NUMA node so memory lands first-touch on the right controller
SIMD8i32 SpinPool WorkerPool CpuTopology
Case study · Nue

An LLM inference engine,
written in Haxe.

Nue runs local language models on the Rayzor runtime. The tokenizer, the quantized matmul kernels, the KV cache and the scheduler are all written in Haxe — a workload people normally assume you have to write in C or Rust.

Every kernel is benchmarked against the Rust version it replaces. When Haxe is slower, that's treated as something to fix in the kernel, the thread pool or the compiler — not a reason to drop back to Rust.

Browse nue/ in the repo
quantized matmul KV cache SpinPool SIMD kernels GGUF
Decode throughput Apple M1 Pro · 16GB
Qwen 0.5B 138tok/s
Llama 1B 90tok/s
Pure Haxe vs the Rust kernel

Qwen2.5-0.5B, interleaved arms, medians, verified with zero FFI calls.

schemeHaxeRust Q6_K · k-quant + Q8_0 135.63 106.30 Q5_0 → INT8 113.82 119.37

Parity is met and beaten on k-quant; INT8 sits within 5% and is closing. FFI is reserved for platform APIs — AMX, CoreML, VNNI — never for kernels Haxe could write.

In progress

Bring your own frontend.

We're working on consuming the official Haxe compiler's output directly and lowering it into Rayzor MIR. Keep the frontend you already trust — full Haxe 4.x, every macro, every library — and get native codegen, ownership and the tiered runtime underneath it.

No rewrite, no second dialect. The same build you run today, ending in machine code.

Follow the discussion ↗
haxe Your existing build, run by the official compiler — same class paths, same macros
typed output Its typed output read directly, instead of Rayzor re-parsing your source
→ MIR Lowered into the same SSA every Rayzor backend already consumes
native Ownership analysis, the optimization pipeline and the tiered runtime, unchanged