JRuby 10, Part 1: What's New

I am very excited to introduce you to JRuby 10, our biggest leap forward since “JRuby 9000” was released almost a decade ago.

With up-to-date Ruby compatibility, support for modern JVM features, and a big cleanup of internal code and external APIs, we believe this is our most important release ever. This article will provide a first look at these improvements and help you get started on your JRuby 10 journey.

Moving Forward

With such a long time since our last major release, we decided JRuby 10 had to make some big moves. As a result, this is the most up-to-date and powerful JRuby release we’ve ever put together. Here’s a few of the major upgrades you’ll see when you move to JRuby 10.

Compatibility jump to Ruby 3.4

It’s been over three years since we released JRuby 9.4 with Ruby 3.1 compatibility, so naturally a version update was in order. Last year we decided it made the most sense for us to target Ruby 3.4, since it would be released late in 2024 around the time we hoped to wrap up JRuby 10.

That meant implementing Ruby 3.2, 3.3, and 3.4 features, and getting literally thousands of new tests and specs passing.

CRuby core class test results

JRuby 9.4 running Ruby 3.1 tests:

4888 tests, 1859373 assertions, 0 failures, 0 errors, 22 skips

JRuby 10 running Ruby 3.4 tests:

5461 tests, 1903359 assertions, 0 failures, 0 errors, 43 skips

Over the past month, we merged our JRuby 10 development branch back to main, and just this week we finally went “green” in CI after hundreds of hours of work. We’re confident this is the most compatible a JRuby “dot zero” release has ever been, and being current on Ruby compatibility means we’ve got more time to work on aggressive optimization plans.

Java up to 21

Like many projects in the Java world, we chose to maintain support for Java 8 for over a decade after it was released, due to challenging issues involving Java 9+ and the new restrictions of the Java Platform Module System. Even though we made sure JRuby supported the latest Java releases, we could only depend upon Java 8-level features. Meanwhile the JDK added powerful enhancements like native function calls (Project Panama) and lightweight threads (Project Loom).

For JRuby 10, we’re finally updating our minimum Java version… to the most recent “long term support” version 21. Many of the JRuby features described in this post are possible because of that move.

We’ve already started to integrate the features that Java 21 provides, and we’re looking forward to bringing ten years of JVM enhancements to Ruby users.

Full optimization by default

Starting with Java 7, JRuby has supported optimizing Ruby code using a feature called “invokedynamic”, which allows us to teach the JVM how Ruby code works. “Indy” is absolutely critical for Ruby performance on JRuby, but it has also taken time to evolve at the JVM level. Because of the extra startup and warmup time required to use indy on older JVMs, JRuby ran by default in a “middle tier” of optimization, using indy only for simple Ruby operations and using slower inline caching techniques for heavier ones. Users had to enable indy with the JRuby flag -Xcompile.invokedyamic.

But no longer!

JRuby 10 runs with full invokedynamic optimization by default. That means you’ll get the best available performance for your JRuby scripts and applications without passing any additional flags.

JRuby default red/black performance, 9.4 vs 10

$ jruby9.4 -v bench/bench_red_black.rb 5
jruby 9.4.12.0 (3.1.4) 2025-02-11 f4ab75096a OpenJDK 64-Bit Server VM 21.0.5+11-LTS on 21.0.5+11-LTS +jit [arm64-darwin]
1.0899240000000001
0.632956
0.604672
0.612468
0.5976049999999999
$ jruby -v bench/bench_red_black.rb 5
jruby 10.0.0.0-SNAPSHOT (3.4.2) 2025-04-09 e2909f9baf OpenJDK 64-Bit Server VM 21.0.5+11-LTS on 21.0.5+11-LTS +indy +jit [arm64-darwin]
1.651375
0.46118200000000004
0.363622
0.23990799999999998
0.177958

For development and testing environments, where aggressive optimizations are usually not helpful and just slow down command-line use, we provide other options…

Startup time improvements

The number one complaint from JRuby users has always been startup time (and to a lesser extent, warmup time of large apps). With the leap to Java 21, we’ve started to leverage a few new JVM features to get JRuby apps starting up more quickly:

  • OpenJDK’s “Application Class Data Store” (AppCDS) allows pre-caching code and metadata during startup to reduce the cost of future commands. JRuby’s main executable will automatically use the right AppCDS flags on Java 21+ to optimize and cache as much as possible. This has halved the startup time of a typical JRuby command, and there’s a lot more we can do to utilize this feature.
  • Project CRaC (Coordinated Restore at Checkpoint) is an experimental JVM feature that allows users to “checkpoint” a running process and launch multiple future processes by restoring that checkpoint. There’s limitations, such as only being able to restore a single process at a time, but when CRaC works for you it can reduce startup time of even large apps to just a few milliseconds. The JRuby launcher supports CRaC with a few flags described in my first “JRuby on CRaC” blog post.
  • Project Leyden is the next-generation “AppCDS”, also storing data like JIT-compiled native code and optimization profiles from previous runs. The goal of Leyden is to eventually save off everything needed to start right up with optimized code, skipping the slow early stages of execution. The JRuby Team will incorporate Leyden flags into our launcher as they become available (with preview support already in Java 24)… and JRuby users will just have to upgrade their JDK to take advantage.

These features combined with our reduced-overhead --dev flag mean JRuby starts up faster than ever before… fast enough to take most of the pain out of command-line development.

JRuby “hello world” startup time, 9.4 vs 10

[] jruby $ time jruby9.4 --dev -e 'puts "Hello, world!"'
Hello, world!
        0.99 real         1.13 user         0.10 sys
[] jruby $ time jruby --dev -e 'puts "Hello, world!"'
Hello, world!
        0.81 real         0.91 user         0.08 sys

Getting Started

Trying JRuby has never been easier! Here’s a quick walkthrough on getting JRuby into your development toolbox.

Install a JDK

The only requirement for JRuby 10 is a Java 21 or higher JDK installation. I personally like the OpenJDK “Zulu” builds from Azul, but there’s excellent and well-supported free binaries from the Eclipse project, Amazon, Microsoft, and Oracle.

Install the JDK in whatever way is most appropriate for your platform… usually that will mean a system-level package on Linux/BSD or an installer on MacOS and Windows. Then just point your JAVA_HOME environment variable at the JDK and JRuby’s launcher will figure out the rest.

Install JRuby

Most Rubyists will be familiar with Ruby managers and switchers like rbenv, rvm, or chruby. JRuby 10 preview snapshots can be usually be installed as “jruby-head” or “jruby-dev”, and after our release as “jruby-10” or just “jruby”.

JRuby is also a JVM-based project (“write once, run anywhere”, remember?), so installing it yourself is as easy as unpacking a tarball or zip and putting the bin dir in your PATH. There’s no build step and no build tools needed to start using JRuby today.

Users of chruby can unpack this tarball into ~/.rubies since it does not support “head” installs.

Try it out

JRuby supports the standard irb REPL, as well as other modern alternatives like pry. Once you have jruby -v working, you can gem install your favorite tools and test them out on JRuby. It’s really that easy.

$ irb
irb(main):001> JRUBY_VERSION
=> "10.0.0.0-SNAPSHOT"
irb(main):002> RUBY_VERSION
=> "3.4.2"
irb(main):003> java.lang.System.get_property("java.version")
=> "21.0.5"

Riding the Rails

Ruby without Rails would be like… well I guess it would still be Ruby, but there’s no doubt Rails is still the most popular use case for Ruby. JRuby has supported Rails since the 1.x era, and we’ve worked with the Rails and JRuby community to keep up with new releases and features. JRuby represents the best way to achieve single-process multicore scaling of Rails applications, and thousands of Rails users around the world rely on it to better utilize precious computing resources.

We’ll publish a post soon that describes how to get started with JRuby on Rails, all the way from generating an app to deploying on Puma or inside a Java application server.

Rails compatibility

Keeping up with Rails is no small feat, and with only a handful of contributors we have tended to lag a bit behind. JRuby currently has database support for ActiveRecord up to 7.1, and work is ongoing to support Rails 8. If you have an interest in helping the JRuby team update our ActiveRecord adapter (ActiveRecord-JDBC, which uses the pure-JVM Java DataBase Connectivity API), please let us know! We’re hoping to have full support for Rails 8 by this summer.

Generating an app

The typical Rails commands should all work on JRuby exactly the same as on standard CRuby, and with our startup time improvements and the –dev flag, we’re able to run those commands faster than any past JRuby version.

Config changes

Only minor configuration changes are required to run a Rails app on JRuby:

  • Switch to the appropriate ActiveRecord-JDBC adapter for your database, in database.yml and in your Gemfile.
  • Configure the Puma server for a number of threads based on the CPU cores available, using “2n+1” as a good rule of thumb.
  • Make sure there’s enough database connections in the pool for the number of Puma threads you configure.

Once you’ve generated a new app or made config changes to your existing app, just bundle and fire it up! JRuby is a true Ruby implementation, and we work very hard to ensure Ruby libraries and applications like Rails work the same as on CRuby.

Integrating with JVM Languages

Half the fun of JRuby comes from taking advantage of the Java platform. Here’s just a few examples of things you can’t do as easily or quickly on any other Ruby implementation.

Ruby on the JVM

We’ve always had a goal of keeping JRuby a standard “JVM language”, runnable on any Java build compatible with our minimum requirement. This means you can deploy JRuby on Linux, MacOS, and Windows, of course, but also unusual and exotic platforms like the BSDs, Solaris, and more. We also can run on any hardware supported by the JVM, which basically means any system with enough memory and at least 32 bit registers is fair game.

This also means JRuby can be deployed anywhere Java applications can be deployed, alongside enterprise Java apps using Spring or Jakarta EE. Ruby and Rails developers can expand their target market to any shop that hosts JVM-based apps… which dwarfs the number of shops that would be comfortable installing the libraries and development tools necessary to run CRuby. JRuby brings the Ruby world into the enterprise, and brings enterprise opportunities to every Rubyist.

JRuby versus Ruby running threaded “tarai” benchmark

$ jruby bench_ractors_tarai.rb 
                      user     system      total        real
serial           21.580000   0.070000  21.650000 ( 21.395228)
threaded         32.690000   0.100000  32.790000 (  4.260730)

$ ruby3.4 --yjit bench_ractors_tarai.rb
                      user     system      total        real
serial           25.037682   0.060370  25.098052 ( 25.257134)
threaded         24.998077   0.055508  25.053585 ( 25.058869)

Calling into Java

Part of running on the JVM is being able to integrate other languages and their libraries into your JRuby apps. With JRuby, you can call Java, Scala, Clojure, Kotlin, and any other JVM language from Ruby with ease. Imagine bring the entire world of JVM languages and libraries to your Ruby app… what could you do when that kind of power?

Using Java’s Swing GUI API from Ruby

java_import javax.swing.JFrame

frame = JFrame.new("Hello Swing")
button = javax.swing.JButton.new("Klick Me!")
button.add_action_listener do |evt|
  javax.swing.JOptionPane.showMessageDialog(nil, <<~EOS)
    <html>Hello from <b><u>JRuby</u></b>.<br>
    Button '#{evt.getActionCommand()}' clicked.
  EOS
end

# Add the button to the frame
frame.get_content_pane.add(button)

# Show frame
frame.set_default_close_operation(JFrame::EXIT_ON_CLOSE)
frame.pack
frame.visible = true

Using JVM libraries

Of course in order to use more than just the standard JDK libraries, you need to be able to download and load them into your app. JRuby provides tools like jar-dependencies to let your JRuby gems use libraries published to Maven Central, Warbler to bundle your app and libraries into a single executable jar or war file (“Web ARchive”), and an enhanced require that loads Java JAR files right into your app. It’s the easiest and most fun way to explore all that the JVM has to offer.

Want to build a cross-platform desktop UI? The JVM has a half-dozen different frameworks for building GUI applications, and with JRuby-supported libraries like Glimmer and JRubyFX, you don’t have to give up Ruby to get there.

Hello World in Glimmer

include Glimmer

shell {
  text "Glimmer"

  label {
    text "Hello, World!"
  }
}.open

Hello World in Glimmer

Interested in building Android apps for mobile or embedded applications? JRuby provides the Ruboto framework for building Android apps in Ruby without having to write a single line of Java or Kotlin.

This also puts you on the leading edge of emerging technologies. As the JVM platform evolves and new features like Leyden, CRaC, SIMD vector operations, GPU integration and native function support in Panama move from experimental to standard, your apps can start using them with a simple JDK upgrade.

You’ve even got a leg up on adding AI capabilities to your app; Ruby APIs for ChatGPT, Claude, Copilot and others are just starting to appear, but there’s dozens of existing JVM libraries for these LLMs and other bleeding edge AI technologies. You can start using AI in your Ruby apps today with JRuby!

What’s Next?

Over the coming weeks, I’ll publish more detailed posts on each of these areas to help you get started as a new JRuby user or to upgrade your existing JRuby applications. We are very proud of the work we’ve done to bring JRuby 10 to life, and I guarantee every Ruby shop can be faster and more scalable by taking advantage of JRuby and the JVM.

Ruby’s future depends on projects like JRuby and creative developers like you. Let’s show them what we can do!

Join the discussion on Reddit!

JRuby Support and Sponsorship

This is a call to action!

JRuby development is funded entirely through your generous sponsorships and the sale of commercial support contracts for JRuby developers and enterprises around the world. If you find my work exciting or believe it is important your company or your projects, please consider partnering with me to keep JRuby strong and moving forward!

Sponsor Charles Oliver Nutter on GitHub!

Sign up for expert JRuby support from Headius Enterprises!

Written on April 9, 2025