Update vs Install
The previous page introduced composer.lock as the file that pins exact package versions.
Composer has two commands that both look at your dependencies, but they treat that lock file very
differently — and mixing them up is one of the most common Composer mistakes a team can make.
composer install and composer update sound similar, but they do very
different jobs.
composer install: Respect the Lock File
composer install looks for a composer.lock file first. If one exists, it
installs the exact versions recorded there — ignoring the version ranges in
composer.json entirely. If no lock file exists yet, it resolves versions from
composer.json and creates one.
composer install
Use composer install when:
- You just cloned a project and need the exact dependencies the rest of the team is using.
- You're deploying to production or staging.
- Your CI/CD pipeline is installing dependencies to run tests or build the app.
composer update: Re-resolve the Newest Allowed Versions
composer update ignores composer.lock completely. It looks at the version
constraints in composer.json, works out the newest versions of every package that still
satisfy those constraints, installs them, and then rewrites composer.lock
to match what it just installed.
composer update
Use composer update when:
- You deliberately want to pull in newer versions of your dependencies.
- You just changed a version constraint in
composer.jsonand need the lock file to catch up. - You're working locally, where you can immediately test the result before committing the new lock file.
Side-by-Side Comparison
composer install | composer update | |
|---|---|---|
Reads composer.lock? | Yes, if it exists | No, ignores it |
| Resolves new versions? | No — uses locked versions | Yes — re-resolves from composer.json |
Rewrites composer.lock? | Only if the lock file didn't exist yet | Always |
| Typical use | Fresh clone, deploys, CI/CD | Deliberate, local upgrades |
| Result is reproducible across machines? | Yes | Not guaranteed — depends what's newest at the moment you run it |
Updating a Single Package
You rarely want to update everything at once. Passing a package name updates just that package (and anything it strictly requires), leaving the rest of your locked versions untouched.
composer update vendor/package
For example, to update only Monolog without touching any other dependency:
composer update monolog/monolog
This is a much safer habit than a blanket composer update, since it limits how much can
possibly change in one step.
composer update in production or inside a
CI/CD pipeline. Because it ignores composer.lock and re-resolves the newest allowed
versions, it can silently pull in a package version with breaking changes — on your production
server, with no local testing first. Deployment pipelines should almost always run
composer install, never composer update.
require-dev keeps testing and debugging tools out of your live app.