Updated September 2022 to match my current Drupal 9 workflow and to make the guide easier to follow.
I've been putting off using Composer for a long time because it seemed too "trendy" and reminded me too much of the framework movement that HTML9 Responsive Boilerstrap JS parodied so well. However on a recent project I've been migrating a site from Drupal 6 to Drupal 8, and Drupal 8 strongly recommends using Composer from the outset so I thought it was time to take the plunge.
In this article I'll walk through how to set up Composer, Drupal 8 (or 9), and Drush in a way that means we can have multiple users running the same centralised version of Drush when appropriate (ie. when a Drupal site isn't set up as a Composer project, or a project doesn't include its own copy of Drush) which means that our team can keep using Drush seamlessly without having to install a separate copy of Composer and Drush for each user or each project on our servers. This approach should also make it easy to keep things up to date and change the configuration later on if needed.
There's a helpful outline on how to install Composer and Drupal 8+ on Drupal.org but I wanted to write a more detailed trail for future reference, including how I came to decide on this specific configuration.
1. Install Composer
Check if Composer is already installed
To check if it's already installed, run composer
in your shell. If you get a bunch of output explaining composers various options, it's already installed. On recent versions of Ubuntu, if it's not installed you'll get "Command 'composer' not found, but can be installed with: sudo apt install composer". However I'd recommend following instructions on the Composer website to download it yourself instead of using apt
because the apt version is often quite old, and it won't be available in the package manager on all systems anyway (for example Debian didn't have a package for it in the standard apt repositories last time I checked).
To check if Composer is installed globally, run which composer
- if you're given the location of the executable (eg. /usr/local/bin/composer
) then it's installed globally and you can skip the following 'Install Composer' step. If there's no response to this command but it is installed, then it's probably installed 'locally' in your home directory (so you'll want to consider removing it from your home directory and installing it globally instead using instructions in the following step).
Install Composer (once per server)
The first option on Composer's Getting Started page is to install Composer locally in your home directory. However, I recommend going for the global install method instead so that we only have to set it up once per server rather than repeating the process for each user on each server.
3. Install Drupal
Follow the instructions on the official guide under the Create a project heading. In our workflow, towards the end of development you should eventually have a Composer project for dev and a Composer project for live. You don't need to worry about setting up a live system until later, but it's a good idea to name them appropriately from the outset - ie. the first one you set up is /var/www/projectname-dev
and then live will be /var/www/projectname-live
- so it's very clear which is which regardless of whether they're on the same server or not.
After following the instructions I had a Drupal 8 site ready to start working with.
I have a composer project directory at /var/www/drupal8/
and it contains:
composer.json
composer.lock
config/
vendor/
web/
The web
directory contains the actual Drupal files that run the site so that needs to web-accessible, whereas everything else should be kept private.
We don't have a compatible version of Drush installed yet but you can complete the Drupal installation process with the standard web interface, or you can install Drush first and then finish installing Drupal on the command line (instructions here).
4. Install Drush in your project
In order to avoid dependency issues, it is best to require Drush on a per-project basis via Composer rather than installing it globally. At time of writing, the drupal/recommended-project
package doesn't automatically install Drush for you, so you'll need to cd
into the root of your composer project (/var/www/drupal8/
in my case) and run composer require drush/drush
. Composer will install a copy of drush that's appropriate to whatever version of Drupal you've just installed.
When it's finished, you should be able to test the 'local' copy of Drush like this - vendor/bin/drush version
- and drush will tell you its version number.
5. Install Drush Launcher
Why?
It is inconvenient to type vendor/bin/drush
in order to execute Drush commands. By installing the drush launcher globally on your local machine, you can simply type drush
on the command line, and the launcher will find and execute the project specific version of drush located in your project's vendor
directory.
Check if Drush Launcher is already installed
Use the following checks to see if Drush Launcher is already installed before attempting to install it. Try running drush --debug
from your home directory. The first line of output should state the Drush Launcher version.
If the server's been set up for Drupal 7 compatibility (as described below), this line should follow shortly after: Calling fallback: /usr/local/bin/drush8
. If it's not set to work with Drupal 7, then you need to cd
into a Composer project that has its own copy of Drush installed in order for it to work.
Install Drush Launcher
Follow these steps to set up the Drush Launcher script globally on your server. This is the recommended method as it only has to be done once per server.
If you don't have permission to move Drush Launcher into /usr/local/bin/
on step 3, the alternative option would be to do the following for each user:
- Follow steps 1 and 2 to download Drush Launcher and make it executable.
- Put Drush Launcher in your home directory instead of in the global location:
mv drush.phar ~/.local/bin/drush
- Add this location to your
$PATH
so your shell can run Drush Launcher without you having to specify its full location:
edit~/.bashrc
and add this line at the end:export PATH="$HOME/.local/bin/:$PATH"
6. Install a fallback version of Drush for Drupal 7 compatibility (once per server, optional)
You can skip this section if you aren't intending to maintain any Drupal 7 sites on your server.
Now we have no global copy of Drush, how do we use Drush on our Drupal 7 sites that don't use Composer? Looking at the compatibility table it seems that Drush version 8 is the last version that's compatible with Drupal 7 so we'll need a copy of that in order to maintain our old Drupal 7 sites. Details on how to install it will follow.
Drush Launcher allows us to set a fallback option to be used when your current directory doesn't have Drush installed as a Composer dependency. The fallback option is set by defining an environment variable eg. by adding a line to .bashrc
in my home directory or putting a file in /etc/profile.d/
. For more info on setting environment variables, see this article.
I considered a few different options here before finding a solution that I was satisfied with...
Option A
Use Composer's global
option to install a fallback instance of Drush that's available to me system-wide.
If I use composer global require/require drush/drush:8.x
it installs the latest version of Drush 8 in /home/vilas/.config/composer/
.
Then I can set the Drush Loader fallback by adding export DRUSH_LAUNCHER_FALLBACK=/home/ben/.config/composer/vendor/bin/drush
to my .bashrc
file.
That works for me, but what about the others on my team who are expecting Drush to keep working the way it did before? I don't really want to install and maintain Composer and Drush for each user on each server!
Option B
Install a global instance of Drush 8 again the "old fashioned way" to use as fallback, but give it a different name so we can have it alongside Drush Launcher. To do this I followed the instructions here but with a few differences:
- Browse to https://github.com/drush-ops/drush/releases and download the drush.phar attached to the latest 8.x release.
- Test your install.
php drush.phar core-status
- Rename to `drush8` instead of `php drush.phar` and move it to a new location. Destination can be anywhere on $PATH.
chmod +x drush.phar
sudo mv drush.phar /usr/local/bin/drush8 - Optional: Enrich the bash startup file with completion and aliases.
drush8 init
- Create a file that sets the fallback for Drush Launcher (multi-line command):
echo '# Based on https://kitson-consulting.co.uk/blog/composer-drush-multi-user-config
export DRUSH_LAUNCHER_FALLBACK="/usr/local/bin/drush8"' >> drush-launcher.sh - Move it to a location where it will be loaded by all users when they log in
sudo chown root:root drush-launcher.sh
sudo mv drush-launcher.sh /etc/profile.d/ - Log out and log in again to load the new environment variables. Use the
env
command to see which environment vars have been set.
This seems to be a relatively elegant option and it works for all users.
Conclusion
I went for option B. To make it easier to tell what's what, I actually made a sym-link pointing to drush-launcher, so now /usr/local/bin/
contains:
drush
- a sym-link pointing to drush-launcher so that we can launch it from anywhere by runningdrush
.drush8
- a manually downloaded copy of Drush 8 for drush-launcher to use as a fall-back.drush-launcher
- the Drush Launcher script which attempts run a local copy of Drush if you're in a Composer project that has one installed, but falls back to the globaldrush8
executable if it can't find one.
Drupal 7 comes to end of life in November 2022, so once we're no longer running Drupal 7 on the server we can skip/undo step 6 and simply use Drush Launcher to find and run whatever version of Drush is installed in your project folder.
That's all folks!
Also of interest: