Need help?
<- Back

Comments (64)

  • dbalatero
    I appreciate that Aaron is focusing on the practical algorithm/design improvements that could be made to Bundler, vs. prematurely going all in on "rewrite in Rust".
  • lamontcg
    The biggest thing that gems could do to make rubygems faster is to have a registry/database of files for each gem, so that rubygems didn't have to scan the filesystem on every `require` looking for which gem had which file in it.That would mean that if you edited your gems directly, things would break. Add a file, and it wouldn't get found until the metadata got rehashed. The gem install, uninstall, etc commands would need to be modified to maintain that metadata. But really, you shouldn't be hacking up your gem library like that ith shellcommands anyway (and if you are doing manual surgery, having to regen the metadata isn't really that burdensome).
  • dang
    Recent and related:How uv got so fast - https://news.ycombinator.com/item?id=46393992 - Dec 2025 (457 comments)
  • rossjudson
    Optimization: Doing nothing is faster than doing something.
  • nightpool
    Really interesting post, but this part from the beginning stuck out to me: Ruby Gems are tar files, and one of the files in the tar file is a YAML representation of the GemSpec. This YAML file declares all dependencies for the Gem, so RubyGems can know, without evaling anything, what dependencies it needs to install before it can install any particular Gem. Additionally, RubyGems.org provides an API for asking about dependency information, which is actually the normal way of getting dependency info (again, no eval required). It would be interesting to compare and contrast the parsing speed for a large representative set of Python dependencies compared to a large representative set of Ruby dependencies. YAML is famously not the most efficient format to parse. We might have been better than `pip`, but I would be surprised if there isn't any room left on the table to parse dependency information in a more efficient format (JSON, protobufs, whatever).That said, the points at the end about not needing to parse gemspecs to install "most" dependencies would make this pretty moot (if the information is already returned from the gemserver)
  • raggi
    It’s definitely possible, I wrote a prototype many many years ago https://ra66i.org/tmp/how_gems_should_be.mov
  • prescriptivist
    I think fibers (or, rather, the Async library) in Ruby tends to be fetishized by junior Rails engineers who don't realize higher level thread coordination issues (connection pools, etc) equally apply to fibers. That said this could be a pretty good use case for fibers -- the code base I use every day has ~230 gems and if you can peel off the actual IO bound installation of all those into non-blocking calls, you would see a meaningful performance difference vs spinning up threads and context switching between them.
  • kimos
    I’ve been squinting at the “global cache for all bundler instances” issue[1] and I’m trying to figure out if it’s a minefield of hidden complication or if it’s actually relatively straight forward.It’s interesting as a target because it pays off more the longer it has been implemented as it only would be shared from versions going forward.[1] https://github.com/ruby/rubygems/issues/7249
  • mberning
    I never found Bundler to be all that slow compared to other package managers.
  • dmix
    tenderlove never misses
  • quotemstr
    Well, now my opinion of uv has been damaged. It...> Ignoring requires-python upper bounds. When a package says it requires python<4.0, uv ignores the upper bound and only checks the lower. This reduces resolver backtracking dramatically since upper bounds are almost always wrong. Packages declare python<4.0 because they haven’t tested on Python 4, not because they’ll actually break. The constraint is defensive, not predictiveMan, it's easy to be fast when you're wrong. But of course it is fast because Rust not because it just skips the hard parts of dependency constraint solving and hopes people don't notice.> When multiple package indexes are configured, pip checks all of them. uv picks from the first index that has the package, stopping there. This prevents dependency confusion attacks and avoids extra network requests.Ambiguity detection is important.> uv ignores pip’s configuration files entirely. No parsing, no environment variable lookups, no inheritance from system-wide and per-user locations.Stuff like this sense unlikely to contribute to overall runtime, but it does decrease flexibility.> No bytecode compilation by default. pip compiles .py files to .pyc during installation. uv skips this step, shaving time off every install.... thus shifting the bytecode compilation burden to first startup after install. You're still paying for the bytecode compilation (and it's serialized, so you're actually spending more time), but you don't associate the time with your package manager.I mean, sure, avoiding tons of Python subprocesses helps, but in our bold new free threaded world, we don't have to spawn so many subprocesses.
  • dboreham
    I've been doing software of all kinds for a long long time. I've never, ever, been in a position where I was concerned about the speed of my package manager.Compiler, yes. Linker, sure. Package downloader. No.
  • amazingman
    If any Bundler replacement isn't using Minimal Version Selection, I'm not interested.