Article
Ruby 4.0.0: Ruby Box, ZJIT, and What Stands Out
A first look at Ruby 4.0.0, including Ruby Box, ZJIT, Ractor updates, and the practical implications for Ruby teams.
The wait is over! Ruby 4.0.0 has officially been released. 🎉
I've been following the development of this version closely, and naruse just dropped the announcement on Christmas day. It introduces some massive changes like "Ruby Box" and "ZJIT" that I think are going to fundamentally change how we build and deploy Ruby applications.
Here is my breakdown of the release and what I find most exciting.
Ruby Box: True Isolation?
The standout feature for me is Ruby Box. It's currently experimental, but the implications are huge. It basically allows you to create isolated containers within a Ruby process.
You enable it with RUBY_BOX=1, and it gives you a Ruby::Box class. Code loaded inside a box is completely isolated—monkey patches, global variables, and even class definitions don't leak out.
I can already see a few killer use cases for this in my own projects:
- Safer Testing: I can run test cases that require heavy monkey-patching without worrying about polluting the global state for other tests.
- Blue-Green Deployment: Running different versions of an app or dependency logic in parallel within the same process? That sounds wild, but it might just work for safer rollouts.
It feels like we're getting a standardized way to do what gems like sandbox tried to do years ago, but built right into the core language.
ZJIT: The Next Generation JIT
We have YJIT, which has been fantastic, but now we have ZJIT. It's a new method-based JIT compiler built in Rust.
Why another one? The goal seems to be raising the performance ceiling even higher than YJIT by handling bigger compilation units. It's not faster than YJIT yet (the core team admits this), but it's designed to be more accessible for contributors.
I probably won't deploy this to production just yet, but I'm definitely going to enable --zjit locally to play around with it.
Ractor is Growing Up
I remember when Ractor was introduced in 3.0. It was promising but rough. In 4.0, it feels like it's finally growing up.
They've added a Ractor::Port class which makes message passing much more intuitive compared to the old yield/take mechanism.
port1 = Ractor::Port.new
port2 = Ractor::Port.new
Ractor.new port1, port2 do |p1, p2|
p1 << 1 # Sending is much cleaner now!
p2 << 11
end
The team is aiming to remove the "experimental" status next year, and honestly, with these performance improvements and the reduction in global lock contention, we might finally see true parallelism become standard in Ruby web servers.
Other Cool Tidbits
There are a ton of smaller language changes, but a few caught my eye:
-
Logical operators at start of line: Finally! We can write multiline conditions like this without syntax errors:
if condition1 && condition2 # ... endThis has bugged me for years.
-
Array#rfind: A more efficient way to find the last element matching a condition. Small, but I'll use it. -
Better Error Highlighting:
ArgumentErrornow shows snippets for both the caller and the callee. Debugging method signature mismatches just got way easier.
What I'd Test First in a Real Ruby App
If I were preparing a production upgrade plan, I would start with isolation and observability rather than chasing benchmark screenshots.
First, I would test Ruby Box in places where teams currently reach for awkward workarounds: plugin-style architectures, background jobs that load untrusted or fast-changing code, and test suites that still depend on global mutation. If Ruby Box holds up there, it could become one of the most important "make this safer to evolve" features in the release.
Second, I would compare YJIT and ZJIT on a real application profile rather than on toy examples. JIT work only matters if it improves the slow paths your users actually hit. That means capturing production-like workloads, measuring memory behavior, and checking deploy ergonomics before deciding whether ZJIT is ready for anything beyond experimentation.
Third, I would look at the upgrade through the lens of team maintenance. Better error messages, more usable concurrency primitives, and clearer runtime boundaries are not just language features. They influence how quickly a team can debug, onboard, and ship. If you're planning a Ruby or Rails upgrade and want a second pair of eyes on the risk, book an intro call.
Final Thoughts
Ruby 4.0.0 feels like a "hardening" release in many ways. It's taking the experimental ideas from 3.x (Ractors, JITs) and giving them solid, usable interfaces.
I'm particularly excited to experiment with Ruby Box. Expect a follow-up post once I've had a chance to build something weird with it.
Merry Christmas and Happy Hacking! 🎄💎
Related Reading
Sources
Related posts
Keep reading in the same neighborhood.
Ukrainian Localization of the Ruby Website
How I helped ship a Ukrainian version of ruby-lang.org, what the contribution process looked like, and why the locale details mattered.
Built-In Authentication in Rails 8: Deep Dive and Comparison
A technical look at Rails 8 authentication, how it compares with Devise, and where the native approach fits well or falls short.
Building Your Personal Brand on GitHub: A Practical Guide
Your GitHub profile is more than a code repository—it's your professional portfolio. Learn how to leverage GitHub's features to build a personal brand that attracts opportunities.