Heroku Ruby Support
Last updated September 04, 2024
Table of Contents
Heroku can run Ruby applications across a variety of Ruby implementations and includes support for framework-specific workflows.
This document describes the general behavior of Heroku as it relates to the recognition and execution of Ruby applications. For framework-specific tutorials, see:
- Getting Started with Ruby on Heroku
- Getting Started with Rails 7 on Heroku
- Getting Started with Rails 6 on Heroku
- Getting Started with Rails 5 on Heroku
General Support
The following support is provided for any type of Ruby application deployed.
Activation
Heroku Ruby Support applies to applications only when the application has a Gemfile
in the root directory. Even if an application has no gem dependencies it must include an empty Gemfile
to document that your app has no gem dependencies.
Particular actions, documented in subsequent sections, are taken depending on the type of application deployed, which is determined by the following rules:
- Presence of
Gemfile
indicates a Ruby application - Presence of
config.ru
indicates a Rack application - Presence of
config/environment.rb
indicates a Rails 2 application - Presence of
config/application.rb
containing the stringRails::Application
indicates a Rails 3 application
Libraries
The following libraries are used by the platform for managing and running Ruby applications and can’t be specified. For application dependency resolution and management, bundler is installed based on the contents of your Gemfile.lock
. If you have a BUNDLED WITH
in your Gemfile.lock
, then you receive a different version of Bundler:
BUNDLED WITH
1.x receive bundler1.17.3
BUNDLED WITH
2.0.x to 2.3.x receive bundler2.3.25
BUNDLED WITH
2.4.x receive bundler2.4.22
BUNDLED WITH
2.5.x and above receive bundler2.5.6
For more information on available settings, see Bundler configuration. For more information on why we only support a specific set of bundler versions, see this article about your Bundler version.
Environment
The following environment variables are set:
GEM_PATH
=>vendor/bundle/#{RUBY_ENGINE}/#{RUBY_ABI_VERSION}
LANG
=>en-us
PATH
=>bin:vendor/bundle/#{RUBY_ENGINE}/#{RUBY_ABI_VERSION}/bin:/usr/local/bin:/usr/bin:/bin
DISABLE_SPRING
=>1
GEM_PATH
is set to the bundler gem vendor directory.
Process Types
The following two process types are always made available:
rake: bundle exec rake
console: bundle exec irb
Build Behavior
When an application is deployed, the build phase configures the underlying Rack or Rails application to use the provisioned database if a config
directory and a RAILS_ENV
or RACK_ENV
environment variable exist. Before ActiveRecord 4.1, which Rails 4.1+ uses, a database.yml
file is created. If a database.yml
file exists, it will be replaced with ActiveRecord 4.1. The database.yml
file is created as Ruby code that dynamically creates its output by parsing the DATABASE_URL
environment variable. In ActiveRecord 4.1+, DATABASE_URL
support is baked in. For more information, see configuring database connections and the pull request that added DATABASE_URL support
At the end of the build, the application is checked for potentially problematic application configuration via the rails runner
interface.
JRuby
For JRuby, you can customize the options passed to the JVM during the build by setting the config var JRUBY_BUILD_OPTS
. A common value is --dev
, which optimizes the runtime for short processes like those executed by Bundler and Rake.
Ruby Versions
Heroku makes a number of different Ruby implementations available. You can configure your app to select a particular runtime.
Default Ruby Version for New Apps
If your Gemfile
doesn’t contain a ruby
entry, you get MRI 3.1.6
.
Default rubies are locked into the app until you specify a Ruby version. For example, if your app is using a default Ruby version of 3.0.3
, you continue to stay on 3.0.3
.
We highly recommend specifying a Ruby version in your Gemfile and not relying on the default Ruby version.
Supported Runtimes
Heroku supports the following Ruby versions and the associated Rubygems. A supported version means that you can expect our tools and platform to work with a given version. It also means you can receive technical support. Here are our supported Ruby versions:
MRI:
3.1.6
, Rubygems:3.3.27
3.2.5
, Rubygems:3.4.19
3.3.5
, Rubygems:3.5.16
When a Ruby version reaches EOL security patches are no longer available. We highly recommend running on a version of Ruby that is actively supported by Ruby core.
JRuby:
9.1.17.0
, Ruby Versions: [2.3.3
]9.2.21.0
, Ruby Versions: [2.5.8
]9.3.15.0
, Ruby Versions: [2.6.8
]9.4.8.0
, Ruby Versions: [3.1.4
]
JRuby versions support the multiple Ruby versions listed. You must specify one in your Gemfile. JRuby runs on the JVM, which is also installed alongside JRuby. For a list of supported Java versions and details on how to configure specific versions, see the Java support article.
For more information on the JVM environment and available JVM options, such as JAVA_TOOL_OPTIONS
, see Heroku’s Java Support on Dev Center.
For advanced JDK options, such as using the Zulu JDK or running jmap
, you must add the heroku/jvm
buildpack as the first buildpack on your app.
Selecting a Runtime
See Ruby Versions for instructions on how to specify your Ruby version.
The Ruby runtime that your app uses is included in your slug, which affects the slug size.
Ruby JIT Support
JIT stands for “Just in Time” compiler. The goal of a JIT implementation is to speed up program execution by providing more efficient code, usually by compiling Ruby code into machine code. Using a JIT will increase memory consumption, and is not guaranteed to make all programs faster. A JIT might make your application slower if the JIT implementation you use is not well suited for your app code.
MJIT
Ruby introduced MJIT in Ruby 2.6 and YJIT in Ruby 3.1. While MJIT works on Heroku, it is not recommended as it will not speed up many real world applications.
YJIT
YJIT is more likely to speed up your application. You can enable YJIT on your Ruby application by running:
$ heroku config:set RUBYOPT="--enable-yjit"
Then verify it worked by running:
$ heroku run bash
~ $ irb
irb(main):001:0> puts RubyVM::YJIT.runtime_stats
{:inline_code_size=>488880, :outlined_code_size=>404622}
Unsupported Ruby Versions
The following is a list of runtime versions present for each stack. The EOL versions are no longer receiving updates from Ruby core and don’t fall under the Heroku Ruby support policy.
On the
heroku-20
stack:- 2.5.x (EOL):
2.5.7
to2.5.9
- 2.6.x (EOL):
2.6.6
to2.6.9
- 2.7.x (EOL):
2.7.1
to2.7.8
- 3.0.x (EOL):
3.0.0
to3.0.7
- 3.1.x:
3.1.0
to3.1.5
- 3.2.x:
3.2.0
to3.2.3
- 3.3.x:
3.3.0
to3.3.4
- 2.5.x (EOL):
On the
heroku-22
stack:- 3.1.x:
3.1.0
to3.1.5
- 3.2.x:
3.2.0
to3.2.3
- 3.3.x:
3.3.0
to3.3.4
- 3.1.x:
On the
heroku-24
stack:- 3.1.x:
3.1.0
to3.1.5
- 3.2.x:
3.2.0
to3.2.3
- 3.3.x:
3.3.0
to3.3.4
- 3.1.x:
This means that while 2.5.9 is no longer “supported” on the Heroku-20 stack, it’s still available for use at your own risk. Heroku always recommends using a supported Ruby version.
If your version of a library, such as Rails, doesn’t work on a supported Ruby version, you can use a service such as Rails LTS. Rails LTS provides a maintained version of older releases for a fee. The Rails LTS project isn’t affiliated with Heroku or with Rails Core.
Rails Version Support
Heroku’s support of Rails versions mirrors the Rails Core version support. Heroku doesn’t sunset availability for older Rails versions. This means that any version of Rails that has ever been able to deploy on the platform can still be used on the platform today. The one limitation is that we can’t promise that older versions of Rails can work on the oldest available Ruby version on a given stack.
For example, if Rails 3.2 can’t run on Ruby 2.4.10 or higher, then you can’t run a Rails 3.2 application on the Heroku-18 stack. We don’t maintain version compatibility information between Ruby and Rails.
If your version of a library, such as Rails, doesn’t work on a supported Ruby version, you can use a service such as Rails LTS. Rails LTS provides a maintained version of older releases for a fee. The Rails LTS project isn’t affiliated with Heroku or with Rails Core.
If you’re not using a Rails Core officially supported version or an LTS supported version, your application likely has security vulnerabilities that are unpatched. We recommend always staying on an officially supported Rails version.
Ruby Applications
Pure Ruby applications, such as headless processes and evented web frameworks like Goliath, are fully supported on Heroku.
Activation
When a deployed application is recognized as a pure Ruby application, Heroku responds with -----> Ruby app detected
.
$ git push heroku master
-----> Ruby app detected
Add-ons
If you created your account before May 15, 2023 or if you asked Heroku Support to enable Heroku Postgres auto-provisioning for your account, see Ruby Database Auto-Provisioning.
Process Types
No default web
process type is created if a pure Ruby application is detected.
Rack Applications
Rack applications behave like Ruby applications with the following additions.
Activation
A root-level config.ru
file specifies the existence of a Rack application. Applications recognized as Rack apps are denoted with a -----> Ruby/Rack app detected
at deploy-time.
$ git push heroku master
-----> Ruby/Rack app detected
Environment
The following additional environment variable is set:
RACK_ENV
=> “production”
Add-ons
Adds the same add-ons as a pure Ruby app.
Process Types
If you don’t include a Procfile
, Rack apps define a web process type at deploy time:
web: bundle exec rackup config.ru -p $PORT
On Heroku, we recommend Puma as the webserver. Regardless of the webserver you choose, always specify the webserver explicitly in the Procfile
on production apps.
As a special case to assist in migration from Bamboo, Ruby apps that bundle the thin
gem get this web process type:
web: bundle exec thin start -R config.ru -e $RACK_ENV -p $PORT
Rails 2.x Applications
Activation
An app is detected as a Rails 2.x app when the Gemfile.lock
file contains a rails
gem, and the gem version is 2.0.0 or later, and earlier than 3.0.0. Apps recognized as Rails 2.x apps are denoted with a -----> Ruby/Rails app detected
at deploy-time.
$ git push heroku master
-----> Ruby/Rails app detected
Environment
The following additional environment variables are set:
RAILS_ENV
=> “production”RACK_ENV
=> “production”
Add-ons
Adds the same add-ons as a pure Ruby app.
Process Types
If you don’t include a Procfile
, Rails 2 apps define a web process type at deploy time:
web: bundle exec ruby script/server -p $PORT
On Heroku, we recommend Puma as the webserver. Regardless of the webserver you choose, always specify the webserver explicitly in the Procfile
on production apps.
As a special case to assist in migration from Bamboo, Ruby apps that bundle the thin
gem get this web process type:
web: bundle exec thin start -e $RAILS_ENV -p $PORT
Additional process types are declared for Rails 2:
console: bundle exec script/console
And if the app has a jobs:work
rake task:
worker: bundle exec rake jobs:work
Plugin Injection in Rails 2
- A Rails stdout plugin is injected.
Rails 3.x Applications
Activation
An app is detected as a Rails 3.x app when the Gemfile.lock
file contains a railties
gem, and the gem version is 3.0.0 or later, and earlier than 4.0.0. Apps recognized as Rails 3.x apps are denoted with a -----> Ruby/Rails app detected
at deploy-time.
$ git push heroku master
-----> Ruby/Rails app detected
Environment
The following additional environment variables are set:
RAILS_ENV
=> “production”RACK_ENV
=> “production”
Add-ons
Adds the same add-ons as a pure Ruby app.
Process Types
If you don’t include a Procfile
, Rails 3 apps define a web and console process type at deploy time:
web: bundle exec rails server -p $PORT
console: bundle exec rails console
On Heroku, we recommend Puma as the webserver. Regardless of the webserver you choose, always specify the webserver explicitly in the Procfile
on production apps.
As a special case to assist in migration from Bamboo, Ruby apps that bundle the thin
gem get this web process type:
web: bundle exec thin start -R config.ru -e $RACK_ENV -p $PORT
Compile Phase
As a final task in the compilation phase, the assets:precompile
Rake task is executed. This task compiles all assets and puts them in your public directory. For more information refer to Rails Asset Pipeline on Heroku.
Plugin Injection in Rails 3
- A Rails stdout plugin is injected.
- A static assets plugin is automatically injected.
If you include the rails_12factor
gem, then no plugin injection is performed at all. All the configurations are made via the gem. Put this gem in your :production
group to avoid a bug in development that causes you to see duplicate logs. This bug has been fixed in later versions of Rails.
Rails 4.x Applications
Activation
An app is detected as a Rails 4.x app when the Gemfile.lock
file contains a railties
gem, and the gem version is 4.0.0.beta or greater, and earlier than 5.0.0. Apps recognized as Rails 4.x apps are denoted with a -----> Ruby/Rails app detected
at deploy-time.
$ git push heroku master
-----> Ruby/Rails app detected
Environment
The following additional environment variables are set:
RAILS_ENV
=> “production”RACK_ENV
=> “production”
Add-ons
Adds the same add-ons as a pure Ruby app.
Process Types
If you don’t include a Procfile
, Rails 4 apps define a web and console process type at deploy time:
web: bundle exec bin/rails server -p $PORT -e $RAILS_ENV
console: bundle exec bin/rails console
On Heroku, we recommend Puma as the webserver. Regardless of the webserver you choose, always specify the webserver explicitly in the Procfile
on production apps.
Compile phase
As a final task in the compilation phase, the assets:precompile
Rake task is executed if you have a assets:precompile
Rake task defined, and don’t have a public/assets/manifest-*.json
file. This task compiles all assets and puts them in your public directory. If the rake detection or the asset compilation task fails, the deploy fails as well. For more information, refer to Rails Asset Pipeline on Heroku.
Plugin Injection in Rails 4
Rails 4 no longer supports plugin functionality, so Heroku’s support for Rails 4 no longer injects any. However, if you don’t include the rails_12factor
gem, a warning is raised. This gem replaces the need for the plugins and ensures that Rails 4 is optimally configured for executing on Heroku.
Rails 5.x Applications
Activation
An app is detected as a Rails 5.x app when the Gemfile.lock
file contains a railties
gem, and the gem version is 5.0.0.beta and greater, and earlier than 6.0.0. Apps recognized as Rails 5.x apps are denoted with a -----> Ruby/Rails app detected
at deploy-time.
$ git push heroku master
-----> Ruby/Rails app detected
Environment
The following additional environment variables are set:
RAILS_ENV
=> “production”RACK_ENV
=> “production”RAILS_LOG_TO_STDOUT
=> “enabled”RAILS_SERVE_STATIC_FILES
=> “enabled”
Add-ons
Adds the same add-ons as a pure Ruby app.
Process Types
If you don’t include a Procfile
, Rails 5 apps define a web and console process type at deploy time:
web: bundle exec bin/rails server -p $PORT -e $RAILS_ENV
console: bundle exec bin/rails console
Regardless of the webserver you choose, always specify the webserver explicitly in the Procfile
on production apps.
Compile Phase
As a final task in the compilation phase, the assets:precompile
Rake task is executed if you have a assets:precompile
Rake task defined, and don’t have a public/assets/manifest-*.json
file. This task compiles all assets and puts them in your public directory. If the rake detection or the asset compilation task fails, the deploy fails as well. For more information, refer to Rails Asset Pipeline on Heroku.
Plugin Injection in Rails 5
Rails 5 no longer supports plugin functionality, so Heroku’s support for Rails 5 no longer injects any. Previously in Rails 4, the gem rails_12factor
was required to enable logging and static file service. New applications now work out of the box. If you’re upgrading an application see Getting Started on Heroku with Rails 5.x.
Rails 6.x Applications
Same as Rails 5.x applications
Rails 7.x Applications
Same as Rails 6.x applications
Node.js support
Many Ruby applications use Node ecosystem tools to generate frontend assets. To support these applications, Heroku recommends placing the heroku/nodejs
buildpack before the heroku/ruby
buildpack to install Node dependencies. To verify this ordering, you can run the following command:
$ heroku buildpacks
=== polar-inlet-4930 Buildpack URLs
1. heroku/nodejs
2. heroku/ruby
If your application is not using the heroku/nodejs
buildpack, you can add it with the following command:
$ heroku buildpacks:add heroku/nodejs -i 1
Then, re-run heroku buildpacks
to verify that heroku/nodejs
comes before heroku/ruby
. You can customize the installed versions of Node and Yarn with the heroku/nodejs
buildpack for your application by specifying them in a package.json
file. For example:
{
"engines": {
"node": "20.9.0",
"yarn": "1.22.19"
}
}
For more information on configuring installed Node versions, see the Heroku Node.js support article on Devcenter.
If your application is not using the heroku/nodejs
buildpack but has the execjs
gem or a package.json
file at the root of your application, then the Ruby buildpack will install a default version of Node. If you have the webpacker
gem or a yarn.lock
file, your app will receive a version of Yarn.
The versions that heroku/ruby
will install if the Node.js buildpack is not being used are:
- Node: 20.9.0
- Yarn: 1.22.19
We do not recommend relying on this long-term behavior as the default versions will change over time. To control the version of Node or Yarn for your application, you must add the heroku/nodejs
buildpack to your application.
Installed Binaries
In addition to the Ruby binary and default tools that are packaged with it (such as rubygems and bundler) some applications need additional binaries to run their applications. Heroku strongly recommends using an explicit buildpack to install such dependencies, but there are some cases where the heroku/ruby
buildpack will install additional binaries. This section lists the binaries it will install and when.
The Ruby buildpack will install a default version of Node.js if a package.json
is at the root of your application and no prior node
binary is found on the path, see the heroku/ruby
Node.js support section for more information. A version of Yarn will be installed if a yarn.lock
file is at the root of your application and no prior yarn
binary is found on the path, see the heroku/ruby
Node.js support section for more information.
Injected Plugins
By default, Heroku injects plugins in Rails 3.x applications to ensure applications get the most out of the Heroku platform. The two plugins that can be injected are rails_stdout_logging
and rails3_serve_static_assets
. To avoid this injection in Rails 3, include the rails_12factor
gem in your application Gemfile:
gem 'rails_12factor'
Stdout
The rails_stdout_logging
gem ensures that your logs are sent to standard out.
Heroku treats logs as streams of events, rather than files. By piping logs to stdout, your logs are captured and consolidated across multiple dynos by Logplex, which makes them available from the command line, $ heroku logs --tail
, or from logging add-ons.
Static Assets
The rails3_serve_static_assets
gem lets the web process serve static assets.
In the default Rails development environment, assets are served through a middleware called sprockets. In production however, most non-Heroku Rails deployments put their Ruby server behind a reverse HTTP proxy server, such as Nginx, which can load balance their sites and can serve static files directly. When Nginx sees a request for an asset such as /assets/rails.png
it grabs it from disk at /public/assets/rails.png
and serve it. The Rails server never sees the request.
On Heroku, Nginx isn’t needed to run your application. Our routing layer handles load balancing while you scale out horizontally. The caching behavior of Nginx isn’t needed if your application is serving static assets through an edge caching CDN.
By default, Rails 4 returns a 404 if an asset isn’t handled via an external proxy, such as Nginx. While this default behavior helps you debug your Nginx configuration, it makes a default Rails app with assets unusable on Heroku. To fix this, we’ve released a gem rails_serve_static_assets
.
This gem, rails_serve_static_assets
, enables your Rails server to deliver your assets instead of returning a 404. You can use this gem to populate an edge cache CDN, or serve files directly from your web app. This gem gives your app total control and allows you to do things like redirects, or setting headers in your Ruby code. To enable this behavior in your app, set this one configuration option:
config.serve_static_assets = true
You don’t need to set this option since this is what this gem does. Now your application can take control of how your assets are served.
Debugger Gems Fail to Install
There are several gems that require specific patch levels of the Ruby they’re running on. This is detrimental to a production app as it locks you into a specific patch level of Ruby and doesn’t allow you to upgrade to receive security fixes.
Heroku releases security patches for Ruby versions as they become available from Ruby core. After we’ve upgraded a Ruby version, your app will get the new version on the next deploy. If your app was using one of these gems, you see a failure when installing gems if we upgraded the version of Ruby you’re using. A failure can look like this:
Installing debugger-linecache
Gem::Installer::ExtensionBuildError: ERROR: Failed to build gem native extension.
Or like this:
Installing debugger
Gem::Installer::ExtensionBuildError: ERROR: Failed to build gem native extension.
The best way to avoid this problem is to not use debugger
or any other debugging gems in production. These gems are designed to hook into the low-level components of a language for dynamically stopping and inspecting execution of running code. Don’t install debugger
in production. Instead, move these gems to your development
group of the Gemfile
:
group :development do
gem "debugger"
end
Then bundle install
, commit to git, and redeploy.