Back to blog
Technical post

Spinel: The Compiled Ruby

Matz released Spinel, an experimental ahead-of-time Ruby compiler that produces standalone native binaries. In benchmarks it reaches up to 86x the speed of miniruby by eliminating runtime type checks through whole-program static analysis.

Spinel: The Compiled Ruby

Matz released Spinel, an experimental ahead-of-time compiler for Ruby that produces standalone native binaries. The numbers from the official benchmarks are hard to ignore: on Conway's Game of Life it runs 86.7x faster than miniruby. That kind of gap is not a tuning win. It comes from a fundamentally different execution model.

Standard CRuby and YJIT work by interpreting or JIT-compiling Ruby at runtime. Every time a variable is used, the VM has to ask what type it is before it can decide what to do with it. Those repeated runtime checks are a large part of why interpreted Ruby has a performance ceiling.

Spinel takes a different path. It runs offline, before the program executes:

  1. Parse the source with Prism
  2. Run whole-program analysis across all files simultaneously
  3. Infer static types from the analysis
  4. Generate optimized C code from the typed AST
  5. Compile that C with Clang or GCC into a standalone native binary

The result is a binary that starts instantly and needs no Ruby runtime. Because types are resolved at compile time, the runtime checks that slow down CRuby are gone entirely.

The benchmark table below is from the official Spinel repository. Lower time is better.

BENCHMARK            SPINEL    MINIRUBY    SPEEDUP
life (Conway's GoL)   20 ms    1,733 ms     86.7x
ackermann              5 ms      374 ms     74.8x
mandelbrot            25 ms    1,453 ms     58.1x
fib (recursive)       17 ms      581 ms     34.2x
nqueens               10 ms      304 ms     30.4x
tarai                 16 ms      461 ms     28.8x
tak                   22 ms      532 ms     24.2x
matmul                13 ms      313 ms     24.1x
sudoku                 6 ms      102 ms       17x
partial_sums          93 ms    1,498 ms     16.1x
fannkuch               2 ms       19 ms      9.5x
sieve                 39 ms      332 ms      8.5x
fasta (DNA seq gen)    3 ms       21 ms        7x

Every benchmark shown is compute-heavy and branchy, exactly the kind of workload where dynamic type dispatch costs the most. Spinel's smallest win is 7x on DNA sequence generation, and its biggest is 86.7x on a grid simulation with tight inner loops.

The trade-off is scope. Static analysis only works when types can be fully inferred at compile time. Ruby's dynamic features like method_missing, eval, define_method with runtime strings, and monkey-patching are either unsupported or limited. Spinel targets the subset of Ruby that behaves predictably, which covers a lot of algorithmic code but not a general Rails application.

Spinel does not replace CRuby. It is a proof of concept for a different point in the design space: what happens if you take Ruby syntax, run it through a whole-program compiler, and hand the result to GCC. The answer, for the right class of programs, is that you get native speed with Ruby ergonomics.

The repository is at github.com/matz/spinel.