Upgrading to Composer 2

Upgrading to Composer 2

If you develop using PHP, there's a very high probability you've come across Composer, the PHP dependency manager. You've likely used it to import libraries like my password validator into your project, or used it to start a completely new project with something like Symfony.

Composer has a long history with the first alpha release appearing in March 2012, before finally becoming a stable release in April 2016. Since then, regular releases have kept it up-to-date for security and performance reasons, but something new was needed. If you search Google for 'composer memory issues', you get nearly 10 million results, including from the Composer project itself. It's a big source of trouble for people working on larger projects, whilst trying to deploy on smaller servers and scale up.

This has been reviewed and addressed by the project which, on 24th October 2020, released Composer 2.0. This is said to bring performance improvements of over 50% (on some projects). It does this by adding CPU and memory performance improvements, and allowing parallel installation of packages.

This release essentially makes Composer 1.x hit end-of-life (and is mentioned in their blog post), so upgrading is going to be highly advised for any environment. Given that I manage a small team of developers, and a small cluster of servers, I need to keep an eye on what's happening with our dependencies and make sure they work for us ahead of upgrading. So here's my findings...

Performance

Performance is the big thing for me. If I can update and/or deploy faster, that's lower down time. Money saved! I also like to tinker and play with Symfony a lot, so I'm usually checking out new packages or creating a new Symfony project (most of which are deleted pretty quickly after I've checked what I needed). So I thought I'd check the performance by comparing a single run checkout of:

  1. My Password Validator project
  2. Symfony website skeleton
  3. Install Laravel

Ahead of running each of the installations, the composer cache was cleared using composer clear-cache to benchmark a completely fresh installation via Composer. The time to run each process is based in seconds, as date is performed before and after the composer require element to get start and end time. This might not be the most scientific method to test with, but it's closer to the real world use-case you're going to get.

Password Validator

This is a really small utility library for checking the entropy of a password. It should be really fast to download as there's not a lot to it in terms of size. This was checked using

date && composer require garybell/password-validator && date

Using Composer v1, this completed in 10 seconds. Longer than I expected given the size of the library, but not too much of an issue. Composer v2 brought this time down to 1 second. reduced by 90%, albeit for a trivial scenario.

A graph showing the speed improvement brought by Composer v2. The time taken to execute this scenario was 90% faster using Composer v2
Comparing composer require garybell/password-validator completion time between Composer v1 and v2

Symfony Website Skeleton

Rather than a simple install, this creates a full project. It includes a lot of additional require calls, so it fairly intensive in terms of installation. This was checked using

date && composer create-project symfony/website-skeleton && date

Due to the nature of the Symfony website-skeleton project, this was not going to be a fast process for either version of Composer, at least that was my expectation. Composer v1 handled the task in a fairly impressive 50 seconds. Faster than I expected. Swapping to v2 reduced this time by around 60%, down to 21 seconds. This is more of a real-world situation for a new project. It always seems slower when you're waiting for the terminal to complete, but those 21 seconds go pretty quick.

A graph showing the near 60% improvement in performance Composer v2 has when running composer create-project symfony/website-skeleton
Performance comparison of Composer v1 and v2 when running composer create-project symfony/website-skeleton

Laravel

Laravel installation via Composer is a particularly interesting use case, as it requires the installation of the Laravel installer, and then a create using the Laravel installer itself, which uses Composer to download other components. This was tested using

date && composer require laravel/installer && ./vendor/laravel/installer/bin/laravel new blog && date

The installation was done this way rather than installing Laravel globally to ensure there wouldn't be a conflict when the Composer v2.0 tests were run.

Laravel, being as popular as it is, is going to be used by digital agencies and enthusiasts all over the globe. The Composer v1 process for a new Laravel took 103 seconds, which seemed like a lifetime when waiting for the terminal to complete. The web artisans reading this will be very pleased that this dropped to 30 seconds in my test. An improvement of over 70%.

A graph showing the performance improvement of Composer v2 over v1 when creating a new Laravel project. An improvement of over 70% was seen.
Over 70% improvement when creating a new Laravel project with Composer v2.

Performance Conclusion

It's entirely fair to say that the improvements made in Composer version 2 are going to bring a significant improvement to anyone when they upgrade. Creating a new project in Symfony or Laravel is going to be significantly faster, and there's little to no delay when adding a new single package to an existing project.

I also compared the performance between versions on a code base I work with for my day job. It's a fairly complicated piece of e-commerce software which is in development at the moment, and has almost 90 packages to install. Under Composer v1 this took 68 seconds to get all of the packages. Time my development team are just sat waiting, doing nothing (ok they will likely be thinking of the task ahead, but still they may get distracted whilst waiting). When I ran composer install using the same composer.json file under v2, this time dropped to 15 seconds. A huge improvement, and massively measurable at any reasonable level of scale.

A graph showing the improvement in performance between Composer version 1 and 2. Improvements from 60-90% are possible.
All 3 tests combined into a single graph

Upgrading Composer

Upgrading composer looks like a straight forward process based on the documentation. It should be a simple case of running composer self-update --2 and letting it run. However my version of Composer returned the error Command "self-update" is not defined.

To get round this I needed to find out where Composer was installed to, and then use the installer to replace the .phar file there. This process looked as follows:

  1. run which composer (output /usr/bin/composer)
  2. run php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
  3. run sudo php composer-setup.php --install-dir=/usr/bin --filename=composer

Once that was complete, running composer --version returned Composer version 2.0.4 2020-10-30 22:39:11. Composer had been updated, but it wasn't as easy as it was made to look on the download page of Composer.

Overall Verdict

Whilst the upgrade of Composer wasn't as easy as I had hoped, the performance improvements are absolutely stellar. Keeping the same commands in place was a great decision, so anyone with automated deployments or other work they have scheduled won't have to go back through and change.

I never noticed any issues when I was running my tests, or working with Composer in the short time between upgrading and this post being published. That's not to say there aren't issues, and that some things aren't broken - I just didn't find them.

My biggest surprise was that there's still support within Composer for PHP 5.3, and the rest of the 5.x version. PHP 5.6 has been officially out of support, even for security fixes, for almost 2 years now. I appreciate that Red Hat do keep adding patches to PHP 5.x for their customers, but I feel holding on to those versions for Composer just encourage people to keep their old systems.

PHP 5.3 hasn't been supported for over 6 years, so I find support for it in a common use package shocking. If it was able to run on PHP 5.3 in an unsupported capacity, I would have less of an issue with it. The following is a snippet from the blog post announcing Composer 2's availability

Composer 2.0 supports PHP 5.3+, which is at this point very outdated and makes the code quite hard to maintain in places. We went through the effort to make sure every Composer user can upgrade to Composer 2...

This means there were architectural compromises made to ensure this compatibility was available. It will be interesting to see whether in Composer 2.2 or later, when PHP 5 support is dropped (actually, anything pre-7.1.3), whether performance improves again, owing to being able to use up-to-date PHP functionality.

Conclusion: tl;dr

Use it like you would version 1, but with the benefit of noticeable and easily measurable performance improvements.