Safeguard
Developer Tools•

Gemfile or gemspec: which one decides the versions you install?

An application locks versions in Gemfile.lock. A gem cannot, since Bundler ignores a gem's own lockfile when resolving. What that means for risk.

Safeguard Security Team
3 min read

For an application, Gemfile.lock decides: it is committed and every deployment installs exactly those versions. A gem is different. When an application depends on your gem, Bundler ignores any Gemfile and Gemfile.lock inside it and resolves your gemspec's runtime dependencies together with the application's.

Who resolves the versions

The RubyGems guide frames it as who is at the end of the chain. An application is the end, so it locks. A library is a link in someone else's chain, so it cannot lock. Your gem runs with whatever versions the consumer's resolution picks.

FileBelongs toPurpose
gemspecA gemName, version, metadata, runtime and development dependencies
GemfileAn application, or a gem's dev setupWhich gems and sources to use
Gemfile.lockWritten by BundlerExact versions for reproducible installs

Why this matters for security

If you publish a gem, loose constraints in the gemspec are normal, and the guide says they should stay wide so your gem coexists with others. That means your users, not you, decide which patched versions of your dependencies they run. If you tightly pin a vulnerable version in a gemspec, you can block your own users from patching.

If you consume gems, remember that a library's tested lock file was never used in your build. Your lock file is the record of what you run.

Steps if you maintain a gem

  1. Keep gemspec runtime constraints wide, but set a sensible lower bound once a fix exists.
  2. Test against a range of dependency versions in CI, not only the latest.
  3. Declare development dependencies in the Gemfile if you use both files, as the guide recommends.
  4. Release a new version when a dependency you rely on has an advisory, and note the minimum safe version.
  5. Protect your publishing account, as in our note on RubyGems account security.

Steps if you ship an application

  1. Commit Gemfile.lock.
  2. Install with frozen mode in CI.
  3. Scan the lock file, not the Gemfile, for known advisories.
  4. Review lock diffs in every dependency pull request.
source "https://rubygems.org"
gemspec
gem "rspec", "~> 3.13"

The layout above is the convention for a gem repository, where the gemspec method pulls runtime dependencies in.

Try it yourself

Click through it at your own pace, or open it full screen. See the full resolved set, which is what you actually run.

Where Safeguard fits

Safeguard's policies and gates can check dependency changes in a pull request before merge. A free scan shows what it finds today.

Quick check

Should a gem commit its Gemfile.lock?

The guide treats it as a separate trade off. Either way, consumers will not use it when they install your gem.

Where do runtime dependencies go in a gem?

In the gemspec, using add_dependency. Development dependencies can go in the gemspec or in the Gemfile.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.