Shopify's YJIT Compiler Matures in Ruby 3.2
Shopify's just-in-time compiler for CRuby, YJIT, has reached a production-ready state with the release of Ruby 3.2. The compiler, which first appeared as an experimental feature in Ruby 3.1, has undergone significant revision over the past year. The work has focused not only on improving execution speed but also on reducing memory overhead, broadening platform support, and making the codebase more maintainable.
The project began in mid-2020 within Shopify's Ruby & Rails Infrastructure team. After roughly a year of development, YJIT delivered approximately 20% speedups on the railsbench benchmark. This early success led to an invitation from CRuby core contributors to upstream the project, and YJIT shipped as part of Ruby 3.1 in December 2021. For Ruby 3.2, the team expanded, adding Takashi Kokubun—a long-time CRuby core member and maintainer of MJIT—along with two other engineers, to push the compiler forward.
A Rust Foundation for Performance
A foundational change during this cycle was the port of YJIT's codebase from C99 to Rust. The motivation was twofold: Rust's safety guarantees are critical when writing low-level systems code like a JIT compiler, and the language's standard library offers richer abstractions than the macro-based dynamic arrays the team had been implementing in C. The port took approximately three months and resulted in a codebase that the team reports is noticeably easier to maintain.
Memory Overhead Cut by Two-Thirds
JIT compilers inherently consume more memory than interpreters because they must generate executable machine code and maintain metadata about that code. The YJIT team found the memory footprint in Ruby 3.1 unacceptable for production deployment at Shopify's scale. Through optimizations to metadata layout, the implementation of a garbage collector for defunct machine code, and lazy allocation of memory pages for code generation, the overhead has now been reduced to roughly one third of the Ruby 3.1 level.
Speedups on Benchmarks and in Production
The performance gains extend beyond reduced memory usage. YJIT in Ruby 3.2 speeds up railsbench by about 38% over the stock Ruby 3.2 interpreter. Because the interpreter itself is faster than it was in 3.1, the cumulative improvement over the Ruby 3.1.3 interpreter is approximately 57%. Independent benchmarking from the Ruby community has also shown significant performance gains.
New Platforms via a Multi-Target Backend
Ruby 3.2 introduces a new YJIT backend that can generate machine code for multiple CPU architectures, adding ARM64 support alongside the existing x86-64. This is particularly relevant for Shopify developers migrating to Apple M1/M2 laptops, who previously could only run YJIT through Rosetta emulation. YJIT now runs natively on those machines, as well as on AWS Graviton processors and Raspberry Pi devices. Notably, YJIT reports even larger speedups on Apple M1 hardware than on Intel x86-64 CPUs.
Related Ruby Core Improvements
Several changes to Ruby's internals in 3.2 complement YJIT's work. Object shapes, a reimplementation of Ruby's internal object representation, enable faster instance variable accesses for both the interpreter and YJIT. A new finer-grained constant cache invalidation mechanism was added to address a production issue where redefined constants triggered large amounts of recompilation. Additional work includes a tool to trace YJIT exits, improved support for various types of Ruby method calls, and garbage collector enhancements that allow for variable-sized object allocation, which improves memory usage and interpreter performance.
From Canary Nodes to Global Deployment
Shopify's goal for YJIT has always been to deploy it on the Storefront Renderer (SFR), the infrastructure serving over 75 million requests per minute. Roughly a year ago, a few SFR nodes began running YJIT to gather statistics under real traffic. This exposed performance issues invisible in benchmark suites. With Ruby 3.2, YJIT was deemed stable enough for broader use. Shopify has now deployed it globally across its entire SFR infrastructure, measuring real-world speedups of 5% to 10% on total end-to-end request completion times, depending on the time of day.
The team acknowledges that YJIT still carries some memory overhead, but considers the speedups worthwhile. One of the compiler's key strengths is its rapid compilation time, which is essential for Shopify's continuous deployment practices—often multiple times per hour. Slow compilation could lead to request timeouts for customers during deployments.
Next Steps for Method Calls and Code Generation
Looking ahead, the team plans to leverage statistics from the global production deployment to guide further optimization. The most significant area of opportunity is method call performance, since typical Ruby code contains many calls to small methods. Potential avenues include implementing a more efficient calling convention and inlining method calls. The team also intends to improve the quality of generated machine code—YJIT currently lacks a dedicated register allocator and does not optimize across basic blocks. Finally, optimizing hash and string operations is on the roadmap, as these are heavily used in web workloads.
Getting Started with YJIT in Ruby 3.2
Ruby 3.2 is available via the official release notes and tarballs. macOS users can install it with Homebrew, and the ruby-install tool works across platforms. The only prerequisite for YJIT is rustc 1.58.0 or newer (or the Rust toolchain) installed before you build Ruby with your preferred tool—brew, ruby-build, ruby-install, etc.
Enable YJIT at runtime with the --yjit command-line flag or by setting the RUBY_YJIT_ENABLE environment variable. For details on YJIT's design and usage, the official documentation is the primary reference.
Background and Further Reading
For those interested in the internals and history of the project, the following talks and articles cover different aspects of YJIT's development:
- Alan Wu's RubyKaigi 2022 keynote: Stories from developing YJIT
- Building a Lightweight IR and Backend for YJIT (RubyKaigi 2022)
- Peter Zhu on Optimizing Ruby's Memory Layout: Variable Width Allocation
- YJIT - Building a new JIT Compiler inside CRuby (RubyConf 2021)
- MJIT, YJIT, and HAML with Takashi Kokubun — Ruby Rogues #573
- Parsers, Interpreters, and YJIT with Kevin Newton
- Shopify Engineering: YJIT: Building a New JIT Compiler for CRuby
- Shopify Engineering: Our Experience Porting the YJIT Ruby Compiler to Rust
Credit goes to the YJIT team and contributors including Alan Wu, Aaron Patterson, Jemma Issroff, Eileen Uchitelle, Kevin Newton, Noah Gibbs, Jimmy Miller, Takashi Kokubun, Ufuk Kayserilioglu, Mike Dalessio, Jean Boussier, John Hawthorn, Rafael França, and many others. YJIT is led at Shopify by Maxime Chevalier-Boisvert, who earned a PhD in compiler design from the University of Montreal in 2016, where she developed Basic Block Versioning (BBV), a JIT compiler architecture designed for dynamically-typed programming languages.
Shopify is committed to open source software. Those interested in similar work can explore openings on the Engineering career page and learn about Digital by Design.



