Package Managers
Each ecosystem's own tool for reading a manifest, writing a lockfile and publishing to a registry, from npm and pip to Cargo and Bundler. Interviewers ask about the one your stack ships with.
on this pageshowhide
explore
- sbtempty
- npmempty
- Install & Lockfileempty
- Scripts & Lifecycleempty
- pnpmempty
- Yarnempty
- Pipempty
- Poetryempty
- Condaempty
- Pipenvempty
- uvempty
- pdmempty
- virtualenvempty
- pyenvempty
- PyPIempty
- Bundler18 questions
- Gemfile Sources & Groups6 questions
- Locking & Updating Gems6 questions
- Bundle Exec & Setup6 questions
- RubyGems11 questions
- Gem Command & Paths5 questions
- Gemspec & Publishing6 questions
- RVM5 questions
- Rbenv5 questions
- Composer20 questions
- Manifest & Constraints5 questions
- Lock File & Installs5 questions
- Autoloader Generation5 questions
- Scripts, Plugins & Audits5 questions
- Packagist5 questions
- Cargoempty
- Cargo.toml Manifestempty
- Features & Profilesempty
- Workspacesempty
- Build Scriptsempty
- Crates.ioempty
- .NET CLIempty
- NuGetempty
- Conanempty
- vcpkgempty
- pub.devempty
- Homebrewempty
questions
64 · 6 sectionsWith Bundler, why can a bare `rake test` load different gem versions than `bundle exec rake test`, and what does `bundle exec` change?
basics
~20 sA bare rake starts through RubyGems, which activates the newest installed rake, not the one Gemfile.lock pins. bundle exec runs Bundler.setup first, so the command sees only the locked versions and only the bundle's gems.
In a Gemfile, what versions does `gem "rack", "~> 3.1"` accept, and how do `"~> 3.1.4"`, `">= 3.1"` and a bare `"3.1.4"` differ?
basics
~20 sIn a Gemfile, ~> 3.1 is the pessimistic operator: at least 3.1 and below 4.0. ~> 3.1.4 allows 3.1.4 up to below 3.2, >= 3.1 has no upper bound at all, and a bare "3.1.4" means exactly = 3.1.4.
With Bundler, what is the difference between `bundle install` and `bundle update` when a committed Gemfile.lock already exists?
basics
~20 sbundle 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.
In Ruby with Bundler, what is the difference between `require "bundler/setup"` and `Bundler.require`, and how do group arguments change each?
basics
~20 srequire "bundler/setup" calls Bundler.setup, which puts the locked gems of all installed groups on the load path but loads none. Bundler.require runs setup and then requires every gem of the named groups, :default when called without arguments.
In a Gemfile, what does putting gems inside `group :test do ... end` declare, and what does `require: false` on a gem change?
basics
~20 sA group labels gems (ungrouped ones are in :default) so installs and Bundler.setup can include or skip them, yet every group still resolves into one Gemfile.lock. require: false keeps the gem installed and loadable but stops Bundler.require from requiring it automatically.
In RubyGems 4, what do gem install, gem list, gem update and gem uninstall do, and does gem update remove the older version?
basics
~20 sgem install puts a gem and its runtime dependencies into GEM_HOME, gem list shows installed versions, gem update adds the newest version beside the old one, and gem uninstall removes a version. Only gem cleanup or uninstall deletes old versions.
In RubyGems, what is a .gemspec file, which fields must it set, and what does gem build produce from it?
basics
~10 sA .gemspec is Ruby code that builds a Gem::Specification: name, version, summary, authors, files, require_paths and dependencies. gem build validates it and packages the listed files into name-version.gem, the file gem push uploads.
In RubyGems, what is the difference between GEM_HOME and GEM_PATH, and where does gem install --user-install put gems?
basics
~10 sGEM_HOME is the single directory gem install writes into; GEM_PATH is the list of directories RubyGems searches for installed gems, and GEM_HOME is always part of it. --user-install writes to Gem.user_dir, such as ~/.gem/ruby/4.0.0.
In a RubyGems gemspec, what is the difference between add_dependency and add_development_dependency, and what goes wrong if you mix them up?
basics
~20 sadd_dependency declares a runtime dependency, installed and activated with your gem. add_development_dependency declares a tool needed only to work on the gem; gem install skips it unless --development is given, and it is never activated.
When you publish version 1.0 of a gem with gem push, how do RubyGems API keys, MFA and --otp work, and which gemspec metadata hardens the release?
basics
~20 sgem push uploads a built .gem using an API key from gem signin or GEM_HOST_API_KEY. With MFA enabled, the server demands a one-time code passed via --otp or GEM_HOST_OTP_CODE. Metadata rubygems_mfa_required and allowed_push_host harden pushes.
With RVM, what do `rvm install 4.0.7`, `rvm use 4.0.7` and `rvm use 4.0.7 --default` each do, and which one survives a new terminal?
basics
~20 srvm install downloads a prebuilt Ruby or compiles one into ~/.rvm/rubies; rvm use switches only the current shell by rewriting PATH and the gem variables; adding --default also records it as the default alias that every new shell loads.
Why did many Ruby teams move from RVM to rbenv, and what exactly changes for a project when they do?
basics
~20 sRVM hooks cd, sources shell code into every session, manages gemsets and system packages, and last tagged 1.29.12 in 2021; rbenv just selects a Ruby and leaves gems to Bundler. Migrating keeps .ruby-version and drops .rvmrc, .ruby-gemset and RVM.
On an inherited server set up with RVM gemsets, a cron job running `cd /srv/billing && bundle exec rake invoices:send` uses the wrong Ruby, though it works over SSH; why, and how do you fix it?
basics
~20 sRVM's selection is environment state set by a shell function your SSH login shell sources; cron's minimal shell never loads it, so no cd hook and no gemset. Use RVM wrappers, rvm in DIR do, or rvm cron setup.
In RVM, what is a gemset, how do `rvm use 4.0.7@billing --create` and the `@global` gemset work together, and where do new gems go?
basics
~20 sA gemset is a named gem directory attached to one installed Ruby. rvm use 4.0.7@billing --create creates and selects ~/.rvm/gems/ruby-4.0.7@billing; new gems install there, while gems in that Ruby's @global gemset stay visible to it.
When you `cd` into a project, how does RVM choose the Ruby and gemset, and why must a `.rvmrc` be trusted first?
basics
~20 sRVM's cd hook walks up from the new directory and loads the first project file it finds, with .rvmrc checked before .ruby-version. A .rvmrc is shell code sourced into your shell, so RVM asks before running it; .ruby-version is plain data.
With rbenv, how do you install a new Ruby version and pin it for one project, and what does each command write to disk?
basics
~10 sRun rbenv install 4.0.7 (supplied by the ruby-build plugin) to build Ruby into ~/.rbenv/versions/4.0.7, then rbenv local 4.0.7 in the project to write .ruby-version; rbenv global writes the machine default to ~/.rbenv/version.
How do rbenv shims route a ruby or bundle call to the right Ruby version, and when must you run rbenv rehash?
basics
~10 srbenv puts ~/.rbenv/shims first on PATH; each shim is a small script that runs rbenv exec, which resolves the selected version and execs that version's executable. rbenv rehash regenerates shims when new executables appear.
In what order does rbenv decide which Ruby version is active, and how do rbenv shell, local and global map onto that order?
basics
~20 srbenv takes RBENV_VERSION first (set by rbenv shell), then the nearest .ruby-version found walking up from the current directory (written by rbenv local), then ~/.rbenv/version (written by rbenv global), and otherwise uses the system Ruby.
Why is rbenv called the lighter alternative to RVM, and how do you isolate gems per project when rbenv has no gemsets?
basics
~20 srbenv only prepends a shims directory to PATH and resolves the version on each command, without wrapping cd or loading heavy shell functions. It has no gemsets: each installed Ruby has its own gem directory, and Bundler's lockfile isolates each project.
A project's .ruby-version pins 4.0.7 under rbenv, yet a newly opened terminal runs the system Ruby there; how do you diagnose and fix it?
basics
~20 sCheck that ~/.rbenv/shims comes first on PATH with type -a ruby; usually the rbenv init line sits in a startup file that shell never reads, or a later PATH edit wins. Then run rbenv version to spot a stray RBENV_VERSION.
In a composer.json, how do you configure psr-4 autoloading for your own code, and what does requiring vendor/autoload.php give you?
basics
~20 sMap a namespace prefix to a directory under autoload.psr-4, for example "App\": "src/", then require vendor/autoload.php once at the entry point. That file registers Composer's class loader for your code and every dependency, and includes any files entries.
In Composer, what is the difference between composer install and composer update, and which one should a deploy run?
basics
~10 scomposer install installs the exact versions in composer.lock; composer update re-resolves composer.json's constraints, rewrites composer.lock with the newest allowed versions, then installs. Deploys and CI run install, production with --no-dev; developers run update deliberately.
In a composer.json, what is the difference between require and require-dev, and when are require-dev packages not installed?
basics
~20 srequire lists packages the code needs at runtime, installed everywhere and passed on to the package's consumers. require-dev lists test and tooling packages; it is root-only, so a dependency's dev list is never installed, and --no-dev builds skip it.
In Composer, what does composer dump-autoload -o change about how classes are found, and why is it for production rather than development?
basics
~20 sdump-autoload -o scans PSR-4 and PSR-0 directories and writes every class into the classmap, so known classes resolve by array lookup, not a filesystem check. It suits production, where code changes only at deploy, not development.
In a composer.json constraint, how does ^1.2 differ from ~1.2, and how do ^1.2.3, ~1.2.3 and ^0.3 behave?
basics
~10 sIn Composer, ^1.2 and ~1.2 are the same range, >=1.2.0 <2.0.0. They differ with three parts: ~1.2.3 means >=1.2.3 <1.3.0 while ^1.2.3 means >=1.2.3 <2.0.0. For 0.x, ^0.3 means >=0.3.0 <0.4.0.
What is Packagist, and what does publishing a first PHP library to it involve?
basics
~20 sPackagist is the public package registry Composer queries by default. To publish, push a repository with a valid composer.json named vendor/name, submit its URL on Packagist, and tag releases; Packagist reads versions from tags and branches.
You pushed tag v1.3.0 of a PHP library on Packagist, but consumers' composer update does not offer 1.3.0; what do you check?
basics
~20 sFirst check whether Packagist re-read the repository, usually a missing hook. Then check whether the tag was skipped for an invalid name, a mismatched version key or missing composer.json. Last, check the consumer's constraint, stability settings and repository order.
How does Packagist turn a Git repository's tags and branches into Composer versions such as 1.2.0, 2.x-dev and dev-main?
basics
~20 sEach valid tag becomes a release version, compared without its leading v, with any -beta or -RC suffix setting stability. Each branch becomes a dev version: 2.x becomes 2.x-dev, other names become dev-name, and extra.branch-alias can map dev-main to 1.0.x-dev.
On Packagist, how do you retire a PHP package by marking it abandoned with a replacement, and what do consumers' Composer runs then show?
basics
~10 sMark the package abandoned, optionally naming a replacement package, rather than deleting it. Existing versions keep installing, but Composer warns that the package is abandoned and suggests the replacement, and composer audit reports it.
Packagist.org serves only public packages; how should a team distribute private PHP packages to its own projects instead?
basics
~20 sKeep private packages off Packagist.org and serve them from a private repository: individual vcs entries for a few packages, a static registry built with Satis, or a hosted private registry. Credentials go in auth.json or environment variables.