Library / SDK
rails/bootsnap avatar
rails/bootsnap

rails/bootsnap: caching Ruby load paths and bytecode to cut Rails boot time

Boot large Ruby/Rails apps faster

2,740 stars211 forksRubyMIT

At a glance

What is it?
Bootsnap is a Ruby gem that caches $LOAD_PATH scans and compiled bytecode, and the README reports boot time reductions of roughly 50% to 75% on large apps. It is a good fit for apps that can write to a cache directory and a poor fit for read-only containers.
Who is it for?
Adopt Bootsnap if your Ruby or Rails app boots slowly, you can mount a writable cache directory, and you are willing to purge tmp/cache/bootsnap* as part of deploys. Skip it in read-only containers where you cannot mount a writable tmpdir, and skip it if you rely on coverage reporting and cannot turn off compile_cache_iseq.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 10 days ago.
What is it written in?
Mainly Ruby, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 24, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The boot cost Bootsnap targets

Ruby resolves require by walking every entry in $LOAD_PATH and testing candidate paths until one exists. On a large application with hundreds of load path entries, that is a long sequence of failed file lookups before the first successful one. The README shows the shape of this: a miss on x/foo.rb followed by a hit on y/foo.rb, then notes to imagine the same pattern with 500 $LOAD_PATH entries instead of two. Bootsnap exists to remove that repeated search.

The second cost is compilation. Ruby compiles source into instruction sequences at load time, and YAML and JSON parsing re-parses the same files on every boot. Bootsnap caches those results too. The audience is anyone running a sizeable Ruby or Rails application, particularly in development where the app is restarted often, and in production where a slow boot delays a deploy or a worker start. The README cites a 50% reduction from roughly 6 to 3 seconds on one Discourse machine, a 50% reduction from 3.6 to 1.8 seconds on a smaller internal app, and about 75% on the Shopify core platform, from around 25 seconds to 6.5 seconds. In that large app, the README attributes roughly 25% of the gain to the compile_cache_* features and 75% to path caching.

Path pre-scanning and compilation caching in Bootsnap

Bootsnap has two mechanisms. The first is path pre-scanning, which the README describes as a minor evolution of bootscale. When Bootsnap initializes, or when $LOAD_PATH changes, Bootsnap::LoadPathCache fetches a list of requirable entries from its cache. If the cache is cold it performs a full scan and stores the result. When code later calls require 'foo', Ruby would normally test x/foo.rb, y/foo.rb and so on; Bootsnap instead looks up the cached requirables for each load path entry and substitutes the fully expanded path Ruby would eventually have chosen. The failed opens disappear.

The second mechanism is compilation caching. Bootsnap implements RubyVM::InstructionSequence.load_iseq to cache compiled bytecode, modifies YAML.load_file to cache the loaded object in MessagePack format (falling back to Marshal when the message uses types MessagePack does not support), and modifies JSON.load_file to cache the loaded object in MessagePack. The README notes that compile_cache_iseq breaks coverage reporting, which is a real cost for teams that run coverage in the same environment.

Both mechanisms write into a cache directory, tmp/cache by default or the path in ENV['BOOTSNAP_CACHE_DIR']. That directory must be writable, and the README states Rails will fail to boot if it is not. Instrumentation is available through Bootsnap.instrumentation, a callback receiving an event and a path, where the event is one of :hit, :miss, :stale or :revalidated.

Installing Bootsnap and booting a Rails app with it

Bootsnap works on macOS and Linux. Add the gem to the Gemfile with require: false so it is not loaded by Bundler's default require pass:

ruby
gem 'bootsnap', require: false

For a Rails app, the README says to add one line to config/boot.rb immediately after require 'bundler/setup'. Loading it as early as possible is what produces the largest gain:

ruby
require 'bootsnap/setup'

After that, boot the app the way you normally do, for example with bin/rails server, and confirm that tmp/cache exists and is writable. If the directory is not writable, the README states Rails will fail to boot; the fix is either to make it writable or to remove the require line, or wrap it in a conditional.

If you are not on Rails, or you want explicit control, require bootsnap directly and call Bootsnap.setup with the options you need:

ruby
require 'bootsnap'
env = ENV['RAILS_ENV'] || "development"
Bootsnap.setup(
  cache_dir:            'tmp/cache',
  ignore_directories:   ['node_modules'],
  development_mode:     env == 'development',
  load_path_cache:      true,
  compile_cache_iseq:   true,
  compile_cache_yaml:   true,
  readonly:             true,
)

To check whether the cache is actually helping, set BOOTSNAP_STATS, which logs hit rate statistics on exit. BOOTSNAP_LOG logs every cache miss to STDERR instead, and the README says the two cannot be used together. The require 'bootsnap/setup' path also reads BOOTSNAP_CACHE_DIR, BOOTSNAP_CONFIG, DISABLE_BOOTSNAP, DISABLE_BOOTSNAP_LOAD_PATH_CACHE, DISABLE_BOOTSNAP_COMPILE_CACHE, BOOTSNAP_READONLY and BOOTSNAP_IGNORE_DIRECTORIES, the last being a comma separated list that defaults to ignoring any directory named node_modules.

Where Bootsnap is the wrong tool

The cache directory requirement is the sharpest limitation. In a read-only container where you are unwilling to mount a writable tmpdir, the README says you should remove the require 'bootsnap/setup' line or wrap it in a conditional. There is no mode that makes Bootsnap work without a writable cache; readonly only stops it from updating entries on a miss or a stale entry, it does not remove the need for the directory.

The second limitation is that Bootsnap never cleans up its own cache. The README is explicit that this is left to you, and that depending on your deployment strategy you may need to periodically purge tmp/cache/bootsnap*. It adds a diagnostic worth remembering: if deploys get progressively slower, this is almost certainly the cause. A team that deploys frequently without purging will accumulate cache entries and see the benefit erode.

Coverage reporting is the third constraint. The README states plainly that compile_cache_iseq breaks coverage reporting. If your test environment depends on coverage, you have to disable that feature there, which removes one of the two mechanisms. Finally, Bootsnap is orthogonal to Spring rather than a replacement: Spring keeps a pre-booted Rails process around to skip parts of boot entirely, while Bootsnap speeds up loading individual source files. The README says the two work well together, so choosing one does not exclude the other.

Bootsnap compared with Spring and bootscale

The closest comparison in the README is Spring. Spring keeps a copy of a pre-booted Rails process on hand so the next invocation skips parts of the boot process altogether. Bootsnap does not keep a process alive; it makes each cold boot cheaper by caching load path scans and compiled artifacts. The practical difference is that Spring helps most when you repeatedly run commands against the same app in development, while Bootsnap helps every process start, including production workers and one-off rake tasks. They are not substitutes.

Bootscale is the other reference point. The README describes the path pre-scanning work as a minor evolution of bootscale, which means the load path caching idea predates Bootsnap. Bootsnap adds the compilation caches on top: ISeq, YAML and JSON. If you only need load path optimization, bootscale covers that narrower ground; Bootsnap's value over it is the second category of caching.

For teams that want no cache directory at all, the honest answer is that neither Bootsnap nor bootscale fits, and Spring is the only one of the three that avoids writing a persistent cache in the app tree, since it holds a process instead.

Maintenance, upgrades and the MIT licence

The repository is not archived, and the last push was on 2026-09-19. Recent releases include v1.26.0 on 2026-09-04, v1.25.0 on 2026-08-08 and v1.24.6 on 2026-08-08. That release cadence suggests the gem is still being adjusted, and the CHANGELOG.md at the repository root is the place to check what changed between versions before upgrading.

The upgrade cost is mostly operational rather than code-level. Because the cache format is internal, a version bump can invalidate existing entries, and because Bootsnap never purges its own cache, an upgrade is a natural moment to remove tmp/cache/bootsnap*. The configuration surface is small: the Bootsnap.setup keyword arguments and the BOOTSNAP_* environment variables listed in the README. Teams that use require 'bootsnap/setup' and never touch the options have almost nothing to migrate.

Bootsnap is MIT licensed. That is a permissive licence, but it is not legal advice, and the LICENSE.txt file in the repository is the authoritative text to read if your organisation has specific licence review requirements.

Editorial conclusion

Adopt Bootsnap if your Ruby or Rails app boots slowly, you can mount a writable cache directory, and you are willing to purge tmp/cache/bootsnap* as part of deploys. Skip it in read-only containers where you cannot mount a writable tmpdir, and skip it if you rely on coverage reporting and cannot turn off compile_cache_iseq. Before rolling it out, verify that BOOTSNAP_STATS reports a useful hit rate on your own app, and confirm that your deploy process actually removes the old cache directory.

Frequently asked questions

How do I install bootsnap in a Rails app?

Add gem 'bootsnap', require: false to the Gemfile, then add require 'bootsnap/setup' to config/boot.rb immediately after require 'bundler/setup'. Loading it as early as possible gives the largest improvement.

What does the bootsnap cache directory need to be?

Bootsnap writes to tmp/cache, or to the path set in ENV['BOOTSNAP_CACHE_DIR'], and the README states that directory must be writable or Rails will fail to boot. In a read-only container you should remove the require line or wrap it in a conditional.

How do I clear the bootsnap cache?

The README says Bootsnap will never clean up its own cache and leaves that to you, so you may need to periodically purge tmp/cache/bootsnap*. It also notes that progressively slower deploys are almost certainly caused by an uncleaned cache.

Does bootsnap work with Spring?

Yes. The README describes them as orthogonal tools: Bootsnap speeds up loading of individual source files, while Spring keeps a pre-booted Rails process on hand to skip parts of the boot process, and the two work well together.

How can I check whether the bootsnap cache is being hit?

Set BOOTSNAP_STATS to log hit rate statistics on exit, or use the Bootsnap.instrumentation callback, which receives an event of :hit, :miss, :stale or :revalidated along with a path. BOOTSNAP_LOG logs all misses to STDERR and cannot be used together with BOOTSNAP_STATS.

Official sources

  1. Issues
  2. License: MIT
  3. rails/bootsnap on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/rails-bootsnap.svg)](https://hysenlabs.com/projects/rails-bootsnap)