
February 27, 2026
For nearly three decades, CRuby (MRI) has been overwhelmingly a C codebase. That stability has been both a strength and a constraint. Recently, however, something genuinely new appeared inside the official Ruby repository:
Parts of Ruby itself are now written in Rust.
This is not theoretical, experimental folklore, or third-party tooling. It is production code shipped with Ruby.
Where Rust Is Actually Used: YJIT
The primary — and currently only major — use of Rust in Ruby core is YJIT (Yet another JIT), Ruby’s production Just-In-Time compiler introduced in Ruby 3.1 and significantly improved in later releases.
📍 In the Ruby source tree, you can find it under:
yjit/
YJIT compiles frequently executed Ruby bytecode into native machine code at runtime to reduce interpreter overhead. Large portions of this subsystem are implemented in Rust.
For a project historically written in C, this is a notable architectural decision.
Why This Component?
A JIT compiler is one of the most complex and risk-sensitive parts of a language runtime. It must:
- Generate executable machine code on the fly
- Manipulate raw memory pages
- Track runtime assumptions
- Integrate tightly with the VM
- Avoid crashes that would terminate the process
Rust offers low-level control comparable to C while enforcing memory safety guarantees that C cannot provide.
A Glimpse of Rust Code in Ruby Core
Below is a simplified excerpt representative of the kind of Rust code used in YJIT (adapted for readability). It shows typical systems-level logic manipulating runtime state:
// Simplified example inspired by YJIT internalspub struct CodeBlock { pub ptr: *mut u8, pub size: usize,}impl CodeBlock { pub fn write_byte(&mut self, offset: usize, value: u8) { unsafe { *self.ptr.add(offset) = value; } }}
This illustrates several key characteristics:
- Direct pointer manipulation
- Explicit memory control
- Use of unsafe blocks where required
- Structured abstractions around low-level operations
Such patterns are common in JIT engines that emit machine instructions dynamically.
How Rust Integrates with the C Runtime
Ruby’s VM (YARV) is still written in C. YJIT operates alongside it, not instead of it.
Conceptually:
Ruby Source ↓YARV Bytecode (C VM) ↓YJIT (Rust) ↓Native Machine Code ↓CPU
If YJIT cannot optimize a code path, execution falls back to the interpreter seamlessly.
This hybrid design allows Ruby to gain performance improvements without rewriting the entire runtime.
Why This Matters
The significance of Rust in Ruby is not its size but its role.
Ruby core historically relied on C for any component requiring low-level control. Introducing Rust signals that:
- The core team is willing to adopt modern systems languages
- Memory safety is becoming a priority even in performance-critical subsystems
- Future runtime components may follow a similar pattern
Major infrastructure projects such as the Linux kernel, Android, and database engines are adopting Rust in comparable ways: selectively, not wholesale.
Not a Rewrite — A Strategic Addition
Important clarifications:
Rust is not used for:
- The main interpreter loop
- The parser
- Garbage collection
- Object model
- Standard library
All of those remain in C.
Rust currently targets components where:
- Complexity is extremely high
- Memory bugs would be catastrophic
- Performance is critical
- Isolation is feasible
YJIT fits that profile perfectly.
A Quiet but Meaningful Shift
For everyday Ruby developers, nothing changes at the API level. No new syntax, no new language constructs, no Rust dependency to install.
Yet under the hood, Ruby is no longer a single-language runtime.
For the first time, modern Ruby ships with a core subsystem implemented in Rust.
This makes the development of Ruby itself part of a broader industry movement toward safer systems programming.
Final Thoughts
Rust’s presence in Ruby core is subtle but historically significant. It does not redefine Ruby’s identity, nor does it signal an imminent rewrite of MRI. Instead, it demonstrates a pragmatic evolution:
Use the right tool for the most demanding parts of the system.
YJIT shows that Ruby can integrate modern low-level technologies without sacrificing compatibility, stability, or developer experience.
Ruby remains Ruby — but its engine room is quietly becoming more modern.
