In Ruby 4.0, what is the difference between a default gem and a bundled gem, and what does gem uninstall do to each?
answer
- both ship with the Ruby release
- specifications/default directory
- gem list shows default:
- cannot be uninstalled because it is a default gem
- gems/bundled_gems
basics
~20 sBoth ship with Ruby 4.0. Default gems such as json and bundler are standard library: gem uninstall refuses them, but a newer copy can sit beside them. Bundled gems such as rake and minitest are ordinary preinstalled gems uninstall removes.
solid answer
~40 sA **default gem** is standard library packaged as a gem: its gemspec lives in `specifications/default` under Ruby's gem directory, `gem list` labels it `default: x.y.z`, and `gem uninstall json` answers `Gem json-2.18.0 cannot be uninstalled because it is a default gem`. You can still `gem update json`; the newer copy is installed beside it and a plain `require "json"` activates the highest installed version. A **bundled gem** (listed in Ruby's `gems/bundled_gems`, such as minitest 6.0.0, rake, csv or irb in 4.0) is a normal gem installed when Ruby is installed: it can be uninstalled, and under Bundler it must be declared in the Gemfile to load. `gem cleanup` also skips default gems.
code
bash · 9 linesgem list json -e
# json (default: 2.18.0)
gem uninstall json
# Gem json-2.18.0 cannot be uninstalled because it is a default gem
gem list rake -e
# rake (13.3.1) <- bundled gem: a regular install
gem uninstall rake # removes itgo deeper
Recall that both kinds ship with Ruby, that default gems cannot be uninstalled, and that bundled gems are ordinary gems you can remove.
Explain where default gem specs live, what gem list and gem uninstall print for them, and how gem update adds a newer copy that require then prefers.
Anticipate upgrade breakage when a library moves from default to bundled, and check gem list and the bundled_gems file before relying on a library being present.
Decide how a team tracks Ruby's shifting default and bundled sets across upgrades, and whether to pin such libraries explicitly rather than rely on what Ruby ships.
## Three layers of what ships with Ruby A Ruby 4.0 install carries library code in three forms: 1. **Core and plain standard library** that is not packaged as a gem at all (for example `RbConfig` or `Socket`). 2. **Default gems**: standard-library code that is also published as a gem. 3. **Bundled gems**: separate gems that the Ruby release preinstalls for you. RubyGems treats the last two very differently, and that difference is what the question is about. ## Default gems - The code sits in Ruby's own library directory, and its gemspec is registered in a special directory, `specifications/default` under `Gem.default_dir`. `Gem::Specification#default_gem?` is true for these. - Examples in Ruby 4.0.7: `json` 2.18.0, `psych`, `openssl`, `prism`, and `bundler` itself (RubyGems installs Bundler as a default gem). - **They cannot be uninstalled.** `gem uninstall json` prints `Gem json-2.18.0 cannot be uninstalled because it is a default gem`. If a regular copy of the same version also exists, the regular copy is removed and RubyGems explains that the default copy was left because default gems can't be removed. - **They can be updated.** `gem update json` installs a newer regular copy beside the default one. When code runs `require "json"` outside Bundler, RubyGems activates the **highest installed version**, so the update takes effect. - `gem list json` shows the label: `json (default: 2.18.0)`, or the newer version followed by the default one after an update. - `gem cleanup` never removes them and reports them as `Skipped default gems`. - Their specs stay visible even when `GEM_PATH` is changed, because they are read from `specifications/default` separately. ## Bundled gems - They are listed in Ruby's source tree in `gems/bundled_gems` with their versions (Ruby 4.0.7: `minitest` 6.0.0, `rake` 13.3.1, `test-unit`, `rbs`, `debug`, `csv`, `logger`, `ostruct`, `irb`, `rdoc` and others). - At install time Ruby installs them as **ordinary gems** into the default gem directory. Nothing marks them as special afterwards. - **They can be uninstalled** with `gem uninstall rake`, and updated like any other gem. - They are not standard library in the default-gem sense: a project that uses Bundler must list them in its Gemfile, or the `require` fails under Bundler. ## Side by side | | Default gem | Bundled gem | |---|---|---| | Ships with Ruby | yes | yes | | Spec location | `specifications/default` | regular `specifications/` | | `gem uninstall` | refused | removes it | | `gem update NAME` | adds a newer copy beside it | adds a newer copy, like any gem | | `gem list` label | `default:` | none | | Needs a Gemfile entry under Bundler | no | yes | ## What happens in a script outside Bundler Outside Bundler both kinds simply load: - `require "json"` finds the file in a default gem and activates that gem, choosing the highest installed version of it. - `require "csv"` finds the file in the installed bundled gem and activates it like any other gem. The difference shows up only when something removes or isolates gems: - After `gem uninstall csv`, `require "csv"` raises `LoadError`, because the bundled gem is really gone. - `gem uninstall json` never gets that far, so `require "json"` keeps working. - A `GEM_PATH` that lists only an empty directory (and no trailing separator) still sees the default gems but no longer sees the bundled ones installed in Ruby's default directory. ## Why the distinction keeps coming up Recent Ruby releases have been moving libraries from the default set to the bundled set, which is how code that relied on a library "just being there" starts failing after an upgrade. Knowing which kind a library is tells you: - whether `gem uninstall` will work (bundled) or be refused (default); - whether the version you get is fixed by Ruby unless you update it (default) or can be removed from the machine entirely (bundled); - whether a Bundler project has to declare it (bundled) or can rely on it (default). To check a specific library, `gem list NAME` shows the `default:` label for a default gem, and Ruby's `gems/bundled_gems` file lists the bundled ones for that release.
- After gem update json, which json does a plain require load outside Bundler?The highest installed version. When a required file belongs to a default gem, RubyGems activates that gem through `Kernel#gem` with no version constraint, which selects the highest installed version, so the newer regular copy wins over the default copy. The default copy stays on disk and is used again if the regular copy is uninstalled.
- How do you tell whether a library is a default gem or a bundled gem on your Ruby?Run `gem list NAME -e`: a default gem shows the `default:` label before its version, a bundled gem shows a plain version. Ruby's source tree also lists bundled gems with their versions in `gems/bundled_gems`, and in code `Gem.loaded_specs["json"].default_gem?` answers for an activated gem.
saying these in an interview costs you the question
- Thinks default gems can be removed with gem uninstall
- Believes a default gem is frozen at the version Ruby shipped
- Treats bundled gems as part of the standard library under Bundler
- Assumes gem cleanup deletes old default gem versions
- Thinks bundled gems are downloaded on first require