Composer is the defacto standard for package management in PHP. It’s simple, effective, and has become ubiquitous in the community.
Important Note: Composer major upgrade fix
Everybody knows that when using Composer you just create a composer.json
file with a list of dependencies and your desired versions, then run composer install
and you’re done.
You then commit the composer.json
to your project and everyone else on your team can run composer install
to install your project dependencies.
We also know that if you want to update your dependencies, you simply run composer update
. This will update the currently installed dependencies to their latest versions (as meets your composer.json
version spec).
This is pretty simple. However, there’s also this composer.lock
file that gets generated at the root of your repository. Why? And what should you do with it?
Do You Know Where Your Lock File Is?
A few weeks ago on Twitter, I noticed that the OpenCFP project doesn’t have a composer.lock
file in it’s repository. “So what,” you might say, “just composer install
and away you go. You’ll get the same dependencies, right?”
Wrong.
The point of the lock file is to record the exact versions that are installed so they can be re-installed. This means that if you have a version spec of 1.*
and your co-worker runs composer update
which installs 1.2.4, and then commits the composer.lock
file, when you composer install
, you will also get 1.2.4, even if 1.3.0 has been released. This ensures everybody working on the project has the same exact version.
Now, you might be thinking: with proper semantic versioning, 1.3.0 (or even 1.2.5) should be backwards compatible because it still conforms to the 1.*
version spec, i.e. the major version number hasn’t changed. So what’s the big deal?
Well, unless you are performing code reviews on every release of every dependency, and their dependencies, and so on and so forth, it’s highly likely that some sort of bug or change will creep in eventually that will break your code. We’re only human, after all.
It’s also pretty common for a project to set a dependency version to rely on dev-master, meaning they pull the most recent changes each time. This means that if anything has been committed since the last time a composer install
was done, then, without a lock file, you will get new third-party code being pulled down.
Again, this is a problem if you’re concerned about your code breaking. And it’s one of the reasons why it’s important to think about Composer as being centered around the composer.lock
file. It is a safety device, and should be used like one.
Install or Update?
People often get confused as to whether they should install
or update
. Once you start to think about them as acting upon the lock file instead of the dependencies, things become much easier to think about.
Running composer install
will:
- Check if a
composer.lock
exists - If not, perform a
composer update
to create one - If
composer.lock
exists, install the specified versions from the lock file
Running composer update
will:
- Check
composer.json
- Determine the latest versions to install based on your version specs
- Install the latest versions
- Update
composer.lock
to reflect the latest versions installed
Either way, after running one of these commands, you should commit the composer.lock
to your version control system to ensure all your collaborators areon the same page.
There is one exception to the rule. In the case of something like the Zend Framework 2 Skeleton App, the dependencies should update when you install. That’s because the Skeleton App is a meta-app. So you want to grab the latest dependencies from which to start developing. Therefore the composer.lock
is not committed to the repo.
Deployment
With the composer.lock
in your repository you should composer install
when deploying. This ensures the same dependencies are used in production as in development. It also means composer doesn’t need to do dependency resolution and version lookups, improving deployment performance.
Having a composer.lock
file also ensures consistency across clusters of servers, if you’re running Composer separately on each machine. It enables you to spin up new instances weeks, or months later, without being concerned about dependency mismatch.
Conclusion
So you see, it’s all about the lock file. If you ever wonder whether to call composer install
, or composer update
, let the lock file guide you. If you associate these commands with how they apply to the content of the lock file (and not the dependencies themselves) you can’t go wrong.
In short, if you ever wonder if you should commit the composer.lock
to version control, the answer is: YES.
P.S. If you haven’t been committing your lock file to revision control: why not? Will you switch to doing so now? We’d love to hear your thoughts!