PHP: The Composer Lock File

Everywhere that I go, conference, the supermarket, the dentist, building sites, people always ask me about the Composer lock file. It's a mystery that seems to cause confusion all across the globe. Well, boys and girls, I'm here today to de-mystify the lock file once and for all.

Composer is a PHP application that manages the versions of the PHP libraries, tools and frameworks that we use in our application. For the purpose of this article, I'm going to assume that you've at least build a composer-powered application previously.

Let's begin with a new project and very much imaginary project. It begins with a composer.json file. This file is used to list the versions of our PHP dependencies that we wish to install. Our composer.json file contains three packages.

{
    "require": {
        "assassins/ezio":   "1.1.0",
        "assassins/edward": "1.1.2",
        "templars/shay":    "1.1.*",
    }
}

We've clearly defined the version of two of our packages, but with our third templates/shay is a little more flexible, and we don't care about the patch version parameter. Anything beginning with 1.1 will do just fine.

Now it's worth noting that these are fake packages. Don't go and try to install them. I promise you, they won't work. I've just been playing way too much Assassin's Creed lately.

You could say that the composer.json is a very 'rough' guide to the versions that should be installed. It's not precise, because we have these wildcard versions available to us. It's a ballpark blueprint for our application dependency hierarchy.

We don't have a composer.lock file at the moment, but the second that we run the composer install command.

Behold, we've executed composer install and the mysterious composer.lock file has appeared. If you take a look inside, you'll notice that it's pretty big!

Now it's time for the big reveal. You see, while your composer.json file is a rough guide to the dependency versions that Composer should install, the composer.lock file is an exact record of the dependency versions that have been installed.

That's right, it's recording what Composer has installed for you, right down to the commit hash. Here's a little example:

"source": {
    "type": "git",
    "url": "https://github.com/templars/shay.git",
    "reference": "98c313c831e5d99bb393ba1844df91bab2bb5b8b"
},

You see that big long string? That's the exact commit version that was installed when Composer followed the directions in your composer.json file. It also keeps track of all the versions of your dependencies' dependencies. Even your dependencies' dependencies' dependencies. Even... Well, you get the idea. Your entire application dependency hierarchy will have their versions 'locked' in your composer.lock file.

Why is this useful? Well it's simple. Go ahead and delete your vendor directory. That will remove all of the installed Composer packages that are your applications dependencies.

It's time to run composer install again. This time, Composer will see that you have a composer.lock file in the directory. Instead of finding compatible versions of your dependencies to fulfil the composer.json file, it will install the exact version of your dependencies as defined in your composer.lock file.

This means that we've got the exact version of our dependencies that we had installed before we deleted the vendor directory. That's pretty nifty, right?

Time and time again I hear the question...

Should I version my composer.lock file?

The answer to that question should now be apparent. If you want to record the exact versions of your dependencies that have been used for your application, then yes you should version your lock file. In most sithations, this will be true.

If you're working with a team, versioning the lock file will ensure that you're all working using the exact same versions of your dependency packages. This can be really useful when debugging errors that happen for only one developer.

If you're deploying your application using git, and you version your lock file, you can be sure that the exact version of your dependencies that you tested locally with, will be used in production.

Why is it so important to be using the exact versions of your dependencies?

Let's consider that you don't version your lock file. You composer install and because of the 1.1.* version of the templars/shay package, Composer installs version 1.1.4.

Between this install, and the time that you deploy to your production environment, the templars/shay team have released version 1.1.5. Ouch! Unfortunately, the 1.1.5 version of the package has a serious bug in it.

When you deploy your application to production, Composer installs 1.1.5 of the package, and your application explodes, destroying the whole universe, as per Abstergo's master plans.

You see, if you'd have versioned your lock file, the composer install on production would have respected the lock file, and used version 1.1.4 of templars/shay that you had tested in production. The world would be safe for the time being.

In a sentence...

The Composer lock file is a guarantee of the dependency versions that will be installed, right down to an individual commit level.

Finally, what would cause the composer.lock file to change? All the time, I see people using composer update whenever they update their composer.json file to get the new packages. This is a bad move! You should be using composer install , because it will install your new package without updating the versions of your other packages. This would be much safer.

Here's a list of some actions that will update your composer.lock file.

  • You run composer install for the first time, and the composer.lock file is updated to the installed versions of the dependencies.
  • You run composer install after adding a new package, and the exact version of the new package is added to the composer.lock file.
  • You run composer update, and all of your packages are updated to their latest versions according to the composer.json. This will update the exact version records in the composer.lock file.
  • You run composer update package/name and the version of the specified package is updated to it's latest version observing the package version hint in composer.json. The exact version in the composer.lock file is updated to respect this.

This means that composer install is a "safe" command, and will only add packages to your composer.lock file.

The command composer update is a "risky" command, because it will directly manipulate the version numbers held within your composer.lock file.

Hopefully, you've now deciphered the mystery of the composer.lock file, and also have a craving to play the Assassin's Creed games. (You should. They are fantastic!)

If this guide has helped you learn a thing or two about the Composer lock file, then please consider sharing this article with your friends, so that they too, will learn the secret behind mankind's greatest mystery since "Why is Kevin Bacon an absolute &%£$£?".

Thanks for reading!