Project

prebake

0.0
The project is in a healthy, maintained state
Prebake speeds up bundle install by skipping native gem compilation. It fetches precompiled binaries for gems like puma, nokogiri, pg, grpc, and bootsnap from a shared cache instead of compiling C extensions from source. Drop-in Bundler plugin - one line in your Gemfile, no other changes needed. Works out of the box with the hosted cache at gems.prebake.in, or self-host with S3-compatible storage (AWS S3, Cloudflare R2, Backblaze B2, MinIO) or Gemstash. Works with Ruby 3.2+ and Ruby 4.0 on any platform.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies
 Project Readme

prebake

Stop compiling. Start installing. Prebake your native gems.

Prebake is a Bundler plugin that speeds up bundle install by skipping native gem compilation. Instead of compiling C extensions from source every time, it fetches precompiled binaries from a shared cache. If the cache doesn't have it yet, Bundler compiles normally and the result is cached for everyone.

Why prebake?

Native gems like puma, nokogiri, pg, grpc, bootsnap, sassc, nio4r, prism, and msgpack compile C extensions on every fresh bundle install. On a typical Rails app, this adds 2-3 minutes to every cold install, including in CI, on new developer machines, and during deployments.

Prebake eliminates this. Once a gem is compiled by anyone, it's cached and served as a prebuilt binary to everyone else. The more people use it, the faster it gets.

Who is this for?

  • Ruby/Rails teams tired of slow bundle install in CI
  • Monorepos and multi-app setups where the same gems are compiled repeatedly across projects
  • Open source projects that want faster contributor onboarding
  • Anyone on Ruby 3.2+ using native gems on Linux or macOS

Installation

Add one line to your Gemfile:

plugin "prebake"

Then run:

bundle install

That's it. No other changes needed. Bundler downloads and activates the plugin automatically. The default http backend uses the hosted cache at https://gems.prebake.in; you do not need to set PREBAKE_HTTP_URL unless you want a different server.

Quick start

Self-hosted with Gemstash

export PREBAKE_BACKEND=gemstash
export PREBAKE_GEMSTASH_URL=http://localhost:9292
export PREBAKE_PUSH_ENABLED=true
bundle install

Self-hosted with S3-compatible storage

export PREBAKE_BACKEND=s3
export PREBAKE_S3_BUCKET=my-prebake-cache
export PREBAKE_PUSH_ENABLED=true
bundle install

Configuration

All configuration is done through environment variables. No code changes required.

Variable Default Description
PREBAKE_ENABLED true Set to false to turn the plugin off without editing the Gemfile (for example in CI or a one-off bundle install). Removing plugin "prebake" also disables it.
PREBAKE_PUSH_ENABLED false Set to true to enable local build + push (for self-hosted setups).
PREBAKE_BACKEND http Cache backend: http, s3 (any S3-compatible: AWS S3, Cloudflare R2, Backblaze B2, MinIO), or gemstash.
PREBAKE_HTTP_URL https://gems.prebake.in URL of the prebake cache service when using the http backend.
PREBAKE_HTTP_TOKEN (none) Optional Bearer token sent with HTTP requests. Use this when your cache server requires authentication (private or self-hosted HTTP endpoints).
PREBAKE_S3_BUCKET (required for s3) Bucket name (AWS S3, Cloudflare R2, Backblaze B2, MinIO, etc.).
PREBAKE_S3_REGION us-east-1 Bucket region.
PREBAKE_S3_PREFIX prebake Key prefix (folder) within the bucket.
PREBAKE_GEMSTASH_URL (required for gemstash) Gemstash server URL.
PREBAKE_GEMSTASH_KEY (none) Gemstash API key.
PREBAKE_LOG_LEVEL warn Log verbosity: debug, info, warn.

How it works

Fetching precompiled gems (consumer)

  1. Bundler starts installing a gem with native extensions (e.g., puma, nokogiri, pg).
  2. Prebake intercepts Gem::Ext::Builder#build_extensions before compilation starts.
  3. A cache key is generated from the gem name, version, platform (for example aarch64-linux), and Ruby ABI version (e.g., 4.0).
  4. The plugin checks the configured backend for a precompiled binary matching that key.
  5. Cache hit: the prebuilt .so/.bundle files are extracted directly, with no compiler needed.
  6. Cache miss: Bundler compiles from source as usual (no impact, same as without the plugin).

Publishing compiled gems (publisher)

When PREBAKE_PUSH_ENABLED=true (for self-hosted setups):

  1. After all gems are installed, the plugin identifies gems that were freshly compiled from source.
  2. For each, it builds a platform-specific .gem file and computes a SHA-256 checksum.
  3. The gem and checksum are uploaded to the backend in the background.
  4. Future bundle install runs by anyone on the same platform get the precompiled version.

Supported platforms (cloud service)

Platform Architecture OS
x86_64-linux x86-64 Linux (glibc)
aarch64-linux ARM64 Linux (glibc)
x86_64-linux-musl x86-64 Linux (musl/Alpine)
aarch64-linux-musl ARM64 Linux (musl/Alpine)

Other platforms are supported for self-hosted setups with PREBAKE_PUSH_ENABLED=true. The first bundle install compiles locally and caches the result for others.

Backend setup

HTTP (default)

Works with the hosted prebake service at gems.prebake.in or any custom HTTP server implementing GET/PUT/HEAD /gems/:key. By default no environment variables are required. To point at another server:

export PREBAKE_BACKEND=http
export PREBAKE_HTTP_URL=https://gems.prebake.in

S3-compatible storage (AWS S3, Cloudflare R2, Backblaze B2, MinIO)

Works with any S3-compatible storage. Requires the aws-sdk-s3 gem.

export PREBAKE_BACKEND=s3
export PREBAKE_S3_BUCKET=my-prebake-cache
export PREBAKE_S3_REGION=us-east-1
export PREBAKE_PUSH_ENABLED=true

For non-AWS providers, set the endpoint:

# Cloudflare R2
export AWS_ENDPOINT_URL=https://<account-id>.r2.cloudflarestorage.com

# Backblaze B2
export AWS_ENDPOINT_URL=https://s3.<region>.backblazeb2.com

# MinIO (self-hosted)
export AWS_ENDPOINT_URL=http://minio.internal:9000

Credentials are resolved via the standard AWS SDK chain (AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY, IAM role, ~/.aws/credentials, etc.).

Gemstash

Gemstash is the official RubyGems caching server. Prebake stores precompiled gems as private gems.

export PREBAKE_BACKEND=gemstash
export PREBAKE_GEMSTASH_URL=http://gemstash.internal:9292
export PREBAKE_GEMSTASH_KEY=my-api-key
export PREBAKE_PUSH_ENABLED=true

Frequently asked questions

Does this work with Ruby 4.0?

Yes. Prebake is designed for Ruby 3.2+ and fully supports Ruby 4.0. Cache keys include the Ruby ABI version so gems compiled for Ruby 4.0 are never mixed with Ruby 3.3.

Is this safe? Can someone inject malicious binaries?

The hosted service only builds from rubygems.org; users cannot push binaries. For self-hosted setups, SHA-256 checksums are verified on download.

Does this replace Gemstash?

No. Gemstash caches all gems (download proxy). Prebake only handles native extension compilation. They work great together: Gemstash speeds up downloads, prebake eliminates compilation.

What gems benefit from this?

Any gem with native C extensions: puma, nokogiri, pg, grpc, bootsnap, sassc, nio4r, prism, msgpack, bcrypt, ffi, eventmachine, websocket-driver, oj, redcarpet, and many more.

Troubleshooting

Enable debug logging to see what the plugin is doing:

PREBAKE_LOG_LEVEL=debug bundle install

Common issues:

  • Backend initialization failed: check your backend URL and credentials. The plugin disables itself gracefully and Bundler continues normally.
  • Checksum mismatch: the downloaded binary doesn't match the stored SHA-256. The plugin automatically falls back to compiling from source.
  • To disable for a single run: PREBAKE_ENABLED=false bundle install.

Compatibility

  • Ruby: 3.2, 3.3, 3.4, 4.0+
  • Bundler: 2.4+
  • OS: Linux (x86_64, aarch64, glibc and musl) via cloud service; other platforms via self-hosted

License

MIT