skip to content

Locking & Updating Gems

Gemfile.lock records the versions, platforms, checksums and Bundler version a Gemfile resolved to; bundle install keeps them and bundle update moves them. Interviewers probe both and CI frozen mode.

on this pageshow

explore

questions

6

With Bundler, what is the difference between `bundle install` and `bundle update` when a committed Gemfile.lock already exists?

level: juniorimportance: must knowfreq 74%

answer

  1. the lockfile wins unless you ask
  2. install reuses locked versions
  3. edited Gemfile entry: only it re-resolves
  4. update unlocks the named gems
  5. bundle update --all for everything

basics

~20 s

bundle install installs exactly the versions Gemfile.lock records and re-resolves only gems whose Gemfile entry changed. bundle update deliberately unlocks the named gems, or every gem with --all, and moves them to the newest versions the Gemfile allows.

solid answer

~40 s

Gemfile.lock is the snapshot of a resolution. `bundle install` respects it: with an unchanged Gemfile it installs the locked versions without resolving again, and after a Gemfile edit it re-resolves only the gems you changed while every untouched gem keeps its locked version and dependencies (Bundler calls this conservative updating). `bundle update rack` is the explicit request to move: it unlocks `rack` plus its dependencies and resolves them to the newest versions the Gemfile constraints permit, then rewrites the lockfile. `bundle update --all` re-resolves everything. So a teammate, CI and production all run `bundle install` and get identical gems, and version bumps happen only when someone runs `bundle update` and commits the new Gemfile.lock.

code

bash · 11 lines
bash
# fresh clone or CI: install exactly what Gemfile.lock records
bundle install

# move one gem (and its dependencies) to the newest version the Gemfile allows
bundle update rack

# re-resolve every gem
bundle update --all

# rewrite Gemfile.lock for one gem without installing
bundle lock --update rack

go deeper

for a junior

Recall the split: bundle install reproduces the lockfile, bundle update moves versions forward. Say that Gemfile.lock is committed so every machine installs the same gems.

for a middle

Explain conservative updating: after a Gemfile edit, install re-resolves only the changed gems and keeps untouched gems with their locked dependencies, and why a targeted update also moves the named gem's dependencies.

for a senior

Show the upgrade discipline: targeted bundle update runs with reviewed lockfile diffs, bundle update --all only as a planned upgrade, and bundle lock --update when the current machine cannot install every gem.

for a principal

Frame the trade-off between small frequent targeted updates and rare bulk upgrades: review cost, blast radius of a transitive bump, and how the team owns the lockfile diff.

## What Gemfile.lock pins A **Gemfile** declares *constraints*: `gem "rack", "~> 3.2"` accepts any 3.x release from 3.2 up. A constraint alone does not name a version, so two machines resolving the same Gemfile on different days can pick different releases. Bundler's answer is **Gemfile.lock**: after it resolves the whole dependency graph, it writes the exact version of every gem, direct and transitive, into that file. Commit it, and the lockfile becomes the source of truth for *which* versions run; the Gemfile only says which versions are *acceptable*. The two everyday commands differ in how much they trust that file. ## What `bundle install` does `bundle install` is the **reproduce** command. The `bundle-install(1)` man page describes three cases: 1. **No Gemfile.lock yet** - Bundler fetches the sources, resolves every dependency, installs the gems and writes a new lockfile. 2. **Lockfile present, Gemfile unchanged** - Bundler uses the dependencies recorded in Gemfile.lock *instead of* resolving. You get byte-for-byte the same versions a teammate got. 3. **Lockfile present, Gemfile edited** - Bundler keeps the locked versions for every gem you did not touch and re-resolves only the gems you changed. The man page calls this **conservative updating**. Conservative updating treats each unchanged gem as an atomic unit *together with its locked dependencies*. If your edit needs a newer version of a dependency that an untouched gem also uses, `bundle install` refuses rather than silently moving the shared dependency; you then run `bundle update` for the gems involved. ## How install notices a Gemfile edit Bundler compares the current Gemfile with what the lockfile recorded: the `DEPENDENCIES` section, the sources, the platforms and any `path` or local `git` gemspecs. When they agree, no resolution runs at all. When they differ, Bundler prints a line such as "Found changes from the lockfile, re-resolving dependencies because the dependencies in your gemfile changed" and re-resolves only what the change requires. That is why a one-line Gemfile edit normally produces a small lockfile diff: the new or changed gem, its own dependencies, and the `DEPENDENCIES` line - nothing else. Reading that diff before committing is the cheapest check that the edit did what you meant. ## What `bundle update` does `bundle update` is the **move forward** command. It ignores the locked versions of the gems you name and resolves them again against the newest releases the Gemfile allows: - `bundle update rack` unlocks `rack` **and its dependencies**, even a dependency another gem shares, and leaves everything else locked. - `bundle update --group test` unlocks the gems declared in the `test` group. - `bundle update --all` throws away the whole locked resolution and resolves everything from scratch. - `bundle update --bundler` moves the Bundler version recorded under `BUNDLED WITH`; `--ruby` moves the locked Ruby version. A bare `bundle update` with no names still updates everything, but Bundler prints a deprecation telling you to pass `--all`; setting `update_requires_all_flag` turns the bare form into an error so nobody upgrades the world by accident. `bundle lock --update rack` performs the same re-resolution but only rewrites Gemfile.lock, without installing anything - handy on a machine that cannot build every native gem. ## Side by side | | `bundle install` | `bundle update <gems>` | `bundle update --all` | |---|---|---|---| | Unchanged gems | keep locked versions | keep locked versions | re-resolved | | Named gems | locked unless their Gemfile entry changed | unlocked with their dependencies | re-resolved | | Gemfile.lock | written only when resolution changed | rewritten | rewritten | | Typical use | clone, CI, deploy, after a Gemfile edit | a deliberate bump | periodic upgrade | ## The workflow that follows - Run `bundle install` on every fresh checkout and in CI; it does not move a locked gem you did not change. - To add a gem, edit the Gemfile (or `bundle add`) and run `bundle install`; commit **both** files. - To upgrade, run `bundle update <gem>` for a targeted bump, review the lockfile diff and run the tests. - Reserve `bundle update --all` for a planned upgrade, because it can move dozens of transitive gems at once. ## Common traps - Deleting Gemfile.lock to "fix" an install re-resolves every gem - the same effect as `bundle update --all`, with none of the review. - Expecting `bundle update rack` to touch `rack` alone: by default its dependencies move too; `--conservative` narrows that. - Expecting `bundle install --force` (alias `--redownload`) to upgrade: it reinstalls the same locked versions.

  • You loosen one gem's constraint in the Gemfile and run `bundle install`. What happens to the other gems?
    They keep their locked versions. `bundle install` re-resolves only the gem whose entry changed and treats every untouched gem as fixed together with its locked dependencies. If the new version needs a dependency that an untouched gem pins differently, install reports it cannot update, and you run `bundle update` for the gems involved.
  • What does `bundle lock --update rack` do that `bundle update rack` does not?
    It re-resolves `rack` and writes the new versions into Gemfile.lock without installing any gem. That is useful when the current machine cannot build some gem, or when you only want the lockfile diff for review; a later `bundle install` then installs what the lockfile says.

saying these in an interview costs you the question

  • bundle install always fetches the newest versions the Gemfile allows
  • bundle update only installs missing gems and leaves locked versions alone
  • Deleting Gemfile.lock is the normal way to upgrade one gem
  • bundle update rack changes rack only, never its dependencies
  • Editing one Gemfile line makes bundle install re-resolve every gem
open as a page

A CI job using Bundler 4 with `BUNDLE_DEPLOYMENT=true` fails at `bundle install`, saying the lockfile can't be updated because frozen mode is set; what happened, and what is the fix?

level: seniorimportance: must knowfreq 55%

basics

~20 s

Frozen mode forbids any change to Gemfile.lock, and the committed lockfile no longer matches the Gemfile, usually because someone edited the Gemfile without committing the regenerated lockfile. Run bundle install on a development machine and commit the updated Gemfile.lock.

open as a page

In a Bundler 4 Gemfile.lock, what do the GEM, PLATFORMS, DEPENDENCIES, CHECKSUMS and BUNDLED WITH sections each record?

level: middleimportance: should knowfreq 42%

basics

~20 s

GEM lists every resolved gem with its exact version; PLATFORMS lists the platforms the resolution covers; DEPENDENCIES repeats the Gemfile's direct requirements; CHECKSUMS stores a sha256 per gem (default on in Bundler 4); BUNDLED WITH names the Bundler version that wrote it.

open as a page

With Bundler, why did `bundle update rack` also change other gems in Gemfile.lock, and what do `--conservative`, `--patch` and `--strict` change?

level: middleimportance: should knowfreq 33%

basics

~20 s

bundle update rack unlocks rack and all of its dependencies, even ones other gems share, so they can move. --conservative unlocks only the named gems; --patch or --minor prefer smaller bumps; --strict forbids going past that level.

open as a page

Why can a Gemfile.lock generated on an Apple-silicon Mac break a frozen Linux CI install, and what does Bundler's `bundle lock --add-platform` do about it?

level: seniorimportance: should knowfreq 40%

basics

~20 s

The lockfile's PLATFORMS lists only arm64-darwin, and frozen mode is not allowed to add the CI machine's platform, so Bundler refuses. bundle lock --add-platform x86_64-linux re-resolves for that platform and records it, without needing a Linux machine.

open as a page

What does Bundler 4's `cooldown` setting do during resolution, and why does it never downgrade a version already pinned in Gemfile.lock?

level: seniorimportance: nice to knowfreq 14%

basics

~20 s

cooldown makes Bundler ignore gem versions published fewer than N days ago when it resolves. It governs adopting new versions only, so versions already in Gemfile.lock stay usable, except for gems you explicitly name on bundle update.

open as a page