TL;DR
A recent investigation compared Bundler's performance to uv and examined lessons from uv's design. The author argues many speed gains are achievable in Bundler without a full rewrite, by changing how downloads and installs are handled and by leveraging existing gem metadata.
What happened
After being asked why Bundler isn't as fast as uv, the author reviewed Andrew Nesbitt’s analysis of uv's performance and applied those ideas to RubyGems and Bundler. The post observes that RubyGems already exposes dependency metadata (a YAML gemspec inside gem archives and an API on RubyGems.org), so Bundler doesn't need to execute package code to learn requirements. The author identifies two concrete bottlenecks: Bundler couples fetching a .gem with installing it, and its installation queue enforces that a gem’s dependencies must be installed before the gem itself, which prevents parallel downloads in dependency chains. A small experiment using a slow gem server showed serial downloads in a -> b -> c dependency trees, costing ~11.8 seconds versus ~4.1 seconds for independent sibling gems. The post proposes decoupling download and install steps and special-casing pure-Ruby gems to allow safer parallelism.
Why it matters
- Faster gem installs reduce developer wait times during setup and CI runs.
- Software design changes (decoupling download from install) could deliver gains without rewriting Bundler in another language.
- Understanding when native build steps are required helps safely expand parallelism without breaking installs.
- Leveraging existing gem metadata avoids unsafe code execution and aligns Bundler with approaches used by other package managers.
Key facts
- The author reviewed Andrew Nesbitt’s post “How uv got so fast” to extract applicable techniques for Bundler.
- RubyGems packages include a YAML gemspec that lists dependencies, and RubyGems.org provides an API for dependency information.
- uv’s speed improvements are not solely due to being written in Rust; design choices matter.
- Bundler currently couples fetching a gem file with installing it, linking download and install operations in one method.
- Bundler’s queue requires a gem’s dependencies to be installed before installing the gem, which blocks parallelism in dependency chains.
- In a test using a slow local gem server (3s per gem response), installing a chain a -> b -> c took about 11.8 seconds.
- Installing three independent gems (d, e, f) against the same slow server completed in about 4.1 seconds, demonstrating available parallelism for siblings.
- Native extensions (extconf.rb) can require dependencies at install time, which is why Bundler enforces dependency-first installation.
- The author suggests splitting installation phases and treating pure Ruby gems differently to increase parallelism.
What to watch next
- Efforts to decouple downloading .gem files from the installation step in Bundler to enable parallel fetching (not confirmed in the source).
- Proposals or patches that special-case pure Ruby gems so they can be installed with fewer ordering constraints (not confirmed in the source).
- Any community discussion about relaxing version or runtime upper-bound checks similar to uv’s treatment of requires-python upper bounds (not confirmed in the source).
Quick glossary
- Bundler: A Ruby dependency manager that resolves and installs gems listed in a Gemfile.
- uv: A fast package installer referenced in the source; noted for design decisions that improve download and resolution speed.
- RubyGems: The package format and ecosystem for Ruby libraries; gems are distributed as tar archives containing a gemspec.
- gemspec: A metadata file inside a gem archive (often serialized as YAML) listing dependencies and other package information.
- Native extension: Code in a gem that must be compiled on install (often driven by an extconf.rb script), which can require dependencies to be present during installation.
Reader FAQ
Did the author conclude Bundler can be as fast as uv?
The author believes Bundler can approach uv's speed if certain bottlenecks are removed, though they allow a margin of error.
Is a Rust rewrite necessary to get the speed improvements?
The post argues many optimizations do not require rewriting Bundler in Rust; design changes can yield large gains.
Why does Bundler install dependencies before gems?
Bundler enforces that order because some gems run Ruby code during installation (native extension build scripts) that may need dependencies already installed.
Are concrete implementation plans or timelines provided?
Not confirmed in the source.
Can Bundler Be as Fast as uv? Posted 3 days ago At RailsWorld earlier this year, I got nerd sniped by someone. They asked “why can’t Bundler be as fast…
Sources
- Can Bundler be as fast as uv?
- Can Bundler Be as Fast as uv? | Lobsters
- Can Bundler Be as Fast as uv?
- Ultimate guide to uv library in Python
Related posts
- Exploring Whether Bundler Can Match uv’s Package Installation Speed
- Python performance and memory numbers every programmer should know
- OpenWorkers: Run Cloudflare Workers-compatible JavaScript on your servers