Ruby performance has come a long way since the early days of Rails. With Ruby 3.4.4, we now have access to production-ready JIT compilation and advanced memory management that can significantly boost your Rails application's performance. At Rails Blueprint, we've implemented these optimizations from day one, and the results speak for themselves.
The Performance Problem
Standard Ruby installations, while developer-friendly, leave performance gains on the table. Most Rails applications run with:
- No JIT compilation - Missing 15-30% performance improvements
- Default memory allocator - Higher memory usage and fragmentation
- Suboptimal garbage collection - More frequent GC pauses
Rails Blueprint addresses all of these issues with a carefully configured Ruby setup.
YJIT: The Game-Changing JIT Compiler
What is YJIT?
YJIT (Yet Another Ruby JIT) is Ruby's production-ready Just-In-Time compiler, introduced in Ruby 3.1 and significantly improved in 3.4. Unlike previous JIT implementations, YJIT:
- Compiles hot code paths to native machine code
- Optimizes incrementally - only the code that needs it
- Maintains Ruby semantics - no behavioral changes
- Delivers consistent gains - 15-30% performance improvement
Real-World Impact
In Rails Blueprint applications, YJIT shines in:
Command Objects: Our heavy use of command objects in
app/commands/ with dry-validation benefits significantly from JIT compilation of repeated business logic.View Components: Component-based views with the view_component gem see faster rendering through optimized template compilation.
Background Jobs: Good Job processing gets a boost from JIT-compiled job execution paths.
Enabling YJIT in Production
Rails Blueprint automatically enables YJIT in production through environment configuration:
# config/environments/production.rb # YJIT is enabled via RUBY_YJIT_ENABLE=1 environment variable # This is set in our deployment scripts and Docker configuration lang-ruby
You can verify YJIT is running:
ruby --yjit -e "puts RubyVM::YJIT.enabled?" # => true lang-bash
jemalloc: Superior Memory Management
Why jemalloc?
Ruby's default memory allocator (typically glibc malloc) is general-purpose but not optimized for Ruby's allocation patterns. jemalloc provides:
- 10-20% memory usage reduction
- Better cache locality for improved performance
- Reduced memory fragmentation
- More predictable allocation patterns
Memory Allocation Patterns in Rails
Rails applications have specific memory patterns that jemalloc handles better:
Small object allocation: Ruby creates many small objects (strings, arrays, hashes) that jemalloc manages more efficiently.
Garbage collection: jemalloc's design reduces GC pressure by minimizing fragmentation.
Request handling: Per-request memory allocation and deallocation patterns benefit from jemalloc's optimizations.
Installation Guide
macOS Installation
# Install jemalloc brew install jemalloc # Install rust (required for YJIT) brew install rust # Install Ruby with optimizations RUBY_CONFIGURE_OPTS="--enable-yjit --with-jemalloc=$(brew --prefix jemalloc)" rbenv install 3.4.4 lang-bash
Ubuntu/Debian Installation
# Install dependencies sudo apt-get update sudo apt-get install -y libjemalloc-dev rustc # Install Ruby with optimizations RUBY_CONFIGURE_OPTS="--enable-yjit --with-jemalloc" rbenv install 3.4.4 lang-bash
Verification
Check Ruby Version:
ruby --version # Expected: ruby 3.4.4 (2025-05-14 revision a38531fd3f) +PRISM [x86_64-...] lang-bash
Verify YJIT is Available:
ruby --yjit -e "puts RubyVM::YJIT.enabled?" # Expected: true lang-bash
Verify jemalloc is Linked (Linux):
ldd $(rbenv which ruby) | grep jemalloc # Expected: libjemalloc.so.2 => /lib/.../libjemalloc.so.2 lang-bash
Verify jemalloc is Linked (macOS):
otool -L $(rbenv which ruby) | grep jemalloc # Expected: jemalloc library path lang-bash
Production Configuration
Docker Setup
Rails Blueprint includes optimized Docker configuration:
# Install jemalloc in production container
RUN apt-get install --no-install-recommends -y curl libjemalloc2 libsqlite3-0 libvips
# Entrypoint script automatically enables jemalloc
#!/bin/bash -e
# Enable jemalloc for reduced memory usage and latency.
if [ -z "${LD_PRELOAD+x}" ] && [ -f /usr/lib/*/libjemalloc.so.2 ]; then
export LD_PRELOAD="$(echo /usr/lib/*/libjemalloc.so.2)"
fi
lang-dockerfileEnvironment Variables
# Enable YJIT RUBY_YJIT_ENABLE=1 # jemalloc is loaded via LD_PRELOAD # This is handled automatically by the entrypoint script lang-bash
Performance Benchmarking
Measuring the Impact
Here's how to benchmark your Rails Blueprint application:
# Create a benchmark script: script/performance_test.rb
require 'benchmark'
def simulate_request_cycle
# Simulate typical Rails Blueprint request:
# 1. Authentication check
# 2. Command object execution
# 3. View component rendering
# 4. Background job enqueue
user = User.find(1)
result = SomeCommand.call(user: user, params: sample_params)
MyComponent.new(data: result.data).render_in(view_context)
SomeJob.perform_later(result.id)
end
# Benchmark with and without YJIT
Benchmark.bm do |x|
x.report("without YJIT") { 1000.times { simulate_request_cycle } }
# Enable YJIT and run again
RubyVM::YJIT.enable
x.report("with YJIT") { 1000.times { simulate_request_cycle } }
end
lang-rubyMemory Usage Monitoring
# Monitor memory usage
require 'objspace'
def memory_usage
ObjectSpace.count_objects
end
# Track memory before and after jemalloc
puts "Memory objects: #{memory_usage[:TOTAL]}"
lang-rubyMonitoring in Production
NewRelic Integration
Rails Blueprint includes NewRelic configuration to monitor performance improvements:
# config/newrelic.yml
production:
app_name: <%= Rails.application.class.module_parent_name %>
license_key: <%= Rails.application.credentials.newrelic_license_key %>
# Track Ruby performance metrics
ruby_vm_stats:
enabled: true
# Monitor garbage collection
gc_profiler:
enabled: true
lang-yamlHealth Endpoint
Monitor performance through the built-in health endpoint:
curl https://yourapp.com/health
lang-bash{
"status": "ok",
"version": {
"basic": "1.2.0"
},
"git_revision": "c011f46f988ea5421454b3897e4b29c14a09861b",
"timestamp": "2025-07-16T10:27:04Z"
}
lang-jsonCommon Issues and Solutions
YJIT Compilation Issues
Problem: YJIT not available after installation
Solution: Ensure Rust is installed and
--enable-yjit flag was used# Check if YJIT is compiled in ruby -e "puts RubyVM::YJIT.respond_to?(:enable)" # Should return: true lang-bash
jemalloc Loading Issues
Problem: jemalloc not being loaded in production
Solution: Verify LD_PRELOAD is set correctly
# Check if jemalloc is loaded lsof -p $ | grep jemalloc lang-bash
Memory Leak Detection
Problem: Memory usage still growing despite jemalloc
Solution: Use memory profiling tools
# Add to Gemfile for debugging group :development do gem 'memory_profiler' gem 'rack-mini-profiler' end lang-ruby
Ruby 3.4 Compatibility
Removed Standard Libraries
Ruby 3.4 removed some standard libraries. Rails Blueprint includes necessary gems:
# Gemfile additions for Ruby 3.4 compatibility gem 'csv' # Removed from Ruby 3.4 stdlib gem 'observer' # Removed from Ruby 3.4 stdlib lang-ruby
Performance Improvements in 3.4
Ruby 3.4 includes additional performance improvements:
- PRISM parser - New default parser with better performance
- Improved garbage collection - More efficient object allocation
- Better memory layout - Optimized object structure
Future Considerations
Ruby 3.5 and Beyond
Keep an eye on upcoming Ruby versions:
- Enhanced YJIT - Continued JIT improvements
- Better memory management - Further allocation optimizations
- Concurrency improvements - Better thread and fiber performance
Application-Specific Optimizations
Consider these Rails Blueprint-specific optimizations:
Command Pattern: Structure business logic to benefit from JIT compilation
Component Architecture: Use view components for better memory efficiency
Background Jobs: Optimize job processing with Good Job and PostgreSQL
Conclusion
Ruby 3.4.4 with YJIT and jemalloc represents a significant performance leap for Rails applications. Rails Blueprint makes these optimizations accessible from day one, delivering:
- 15-30% performance improvements through YJIT
- 10-20% memory usage reduction with jemalloc
- Production-ready configuration out of the box
- Monitoring and verification tools included
The performance benefits compound over time as YJIT learns your application's hot paths and jemalloc optimizes memory allocation patterns. Combined with Rails Blueprint's modern architecture (Hotwire, ViewComponent, Good Job), you get a Rails application that's not just feature-complete but performance-optimized.
Ready to experience these performance improvements? Get started with Rails Blueprint and feel the difference optimized Ruby can make.