Last updated October 29, 2018

When managing your Drupal project with Composer you'll use Composer commands to download (require) modules and themes that you want to install, as well as issuing commands to keep those modules and themes up-to-date when new versions are released.

In this tutorial we'll:

  • Cover step-by-step instructions for performing common Composer tasks for a Drupal application
  • Install and update Drupal projects (core, modules, themes, profiles, etc.) using Composer
  • Convert an existing application to use Composer

By the end of this tutorial you should know how to use Composer to install, and update, Drupal modules and themes.

Goal

Create a new Composer-managed Drupal application and install some Drupal modules and themes.

Prerequisites

  • The latest version of Composer. Use composer self-update to update Composer.
  • For existing Drupal applications, configure your composer.json file to work with a Drupal application, as per instructions in Composer Configuration for Drupal
  • For existing Drupal applications, execute all commands from your repository root directory.

Creating a new Drupal application

The simplest way to create a brand new Drupal application using Composer is to start from a template. Composer's create-project command is intended to do exactly that. When you execute composer create-project some/project, it will clone some/project and use it as a template for your new project.

Your new project will not depend on (require) some/project. Instead, some/project will merely be used as a starting point. For instance, the composer.json file in some/project will become the initial composer.json file in your new project. After that, some/project will effectively never influence or interact with your new project again.

There are a few popular "templates" for starting a new Drupal application with Composer. You can find the full list in Using Composer to manage Drupal site dependencies on Drupal.org. Note that the official drupal/drupal project is deprecated and not recommended. It will generate a codebase that cannot be easily upgraded via Composer. Do not use it.

In this tutorial, we will use the most versatile and recommended solution, drupal-composer/drupal-project. This template provides much of the configuration covered in Composer Configuration for Drupal out of the box, as well as a few additional features.

To create a new Drupal application that uses drupal-composer/drupal-project as a template, execute:

$ composer create-project drupal-composer/drupal-project:8.x-dev my-project --stability dev --no-interaction
$ cd my-project

See drupal-composer/drupal-project documentation for more information on its features.

Start using Composer to manage an existing Drupal application

Taking an existing Drupal application that is NOT managed with Composer and beginning to manage it with Composer can be a little tricky. The exact method of implementation depends on the directory structure of your Drupal application, and it may require additional steps to handle edge cases that are not addressed in this tutorial.

There are multiple tools that automate the "composerization" process for you:

  1. The Composerize Drupal Composer plugin (recommended).
  2. Drupal Console's composerize command.
  3. The Composerize module.

If none of these tools work for you, the following manual steps should get you started.

Enter your repository's root directory, where .git lives.

It is extremely important that you execute commands from the correct directory.

For some projects, the root directory may directly contain the Drupal core directory. In other projects, the root directory may be an additional level up such that core lives in docroot/core, web/core, etc.

Remove any vestigial composer.json files or vendor dirs

Your entire application should have exactly one composer.json file and exactly one vendor directory. If there is already a vestigial composer.json file or vendor directory that are unused, remove them.

$ cd path/above/core/dir
$ find . -name "composer.json" -exec rm -rf {} \;
$ find . -name "composer.lock" -exec rm -rf {} \;
$ find . -name "vendor" -exec rm -rf {} \;

It's ok if these commands emit warnings like No such file or directory.

Create a new composer.json file using the following as a template:

{
  "name": "me/my-project",
  "license": "proprietary",
  "type": "project",
  "repositories": {
    "drupal": {
      "type": "composer",
      "url": "https://packages.drupal.org/8"
    },
    "asset-packagist": {
      "type": "composer",
      "url": "https://asset-packagist.org"
    }
  },
  "require": {
    "composer/installers": "^1.2.0",
    "cweagans/composer-patches": "^1.6.4",
    "drupal/composerize": "1.x-dev",
    "drupal-composer/drupal-scaffold": "^2.4",
    "oomphinc/composer-installers-extender": "^1.1",
    "wikimedia/composer-merge-plugin": "^1.4.1"
  },
  "require-dev": {
    "drupal/console": "^1.0.2",
    "drush/drush": "^9.0.0"
  },
  "extra": {
    "enable-patching": true,
    "installer-types": ["bower-asset", "npm-asset"],
    "installer-paths": {
      "docroot/core": ["type:drupal-core"],
      "docroot/modules/contrib/{$name}": ["type:drupal-module"],
      "docroot/modules/custom/{$name}": ["type:drupal-custom-module"],
      "docroot/profiles/contrib/{$name}": ["type:drupal-profile"],
      "docroot/profiles/custom/{$name}": ["type:drupal-custom-profile"],
      "docroot/themes/contrib/{$name}": ["type:drupal-theme"],
      "docroot/themes/custom/{$name}": ["type:drupal-custom-theme"],
      "docroot/libraries/{$name}": ["type:drupal-library", "type:bower-asset", "type:npm-asset"],
      "drush/contrib/{$name}": ["type:drupal-drush"],
      "special/package/dir/": ["my/package"]
    },
    "merge-plugin": {
      "include": [
        "docroot/modules/custom/*/composer.json"
      ],
      "replace": false,
      "ignore-duplicates": true
    },
    "patches": {}
  },
  "minimum-stability": "dev",
  "prefer-stable": true
}
  1. The sample above assumes that Drupal is contained in a docroot subdirectory. Modify all strings containing "docroot" to match your directory structure correctly.
  2. Replace the value of "name" with the name of your project.
  3. composer require drupal/core:[your-version-of-core]. E.g., composer require drupal/core 8.5.3.

You now have a functional composer.json file that appropriately requires Drupal core and the various plugins required to manage a Drupal site with Composer.

Now, you must use Composer to manage all of your required contributed projects (modules, themes, profiles, etc.). This is a manual process that requires your review.

To require an individual project, use the command composer require drupal/[project-name]. This will download the latest stable version, which may actually be an upgrade. If you'd prefer to download an exact version, run composer require drupal/[project-name] [exact-version].

Repeat this command for every contributed Drupal project required by your application.

You should also repeat this for any third-party libraries that may live in docroot/libraries. See the heading, Handling front end dependencies, in Composer Configuration for Drupal for more information.

To speed up this process, you may use drush to generate a list of all installed Drupal projects. To do this, you must have Drupal installed on the local machine. Drush will query Drupal's database to determine which projects are available.

$ ./vendor/bin/drush pml --no-core --status=enabled

 ------------------ ---------------------- --------- ---------
  Package            Name                   Status    Version
 ------------------ ---------------------- --------- ---------
  Chaos tool suite   Chaos tools (ctools)   Enabled   8.x-3.0
 ------------------ ---------------------- --------- ---------

Next, we will follow best practices and remove your contributed modules from version control.

Create a new .gitignore or modify an existing one by adding the following lines:

docroot/core
docroot/modules/contrib
docroot/themes/contrib
docroot/profiles/contrib
docroot/libraries

Next, remove these from version control:

git rm --cached docroot/core
git rm --cached docroot/modules/contrib
git rm --cached docroot/themes/contrib
git rm --cached docroot/profiles/contrib
git rm --cached docroot/libraries
git rm --cached vendor

It's ok if these commands emit an error like fatal: pathspec 'vendor' did not match any files. That just means there was nothing to remove.

That's it! You are now managing all of your site dependencies with Composer. Be sure to continue reading and learn how to correctly deploy this application to a production environment.

Install a new Drupal package via Composer

To install a new Drupal package, first ensure that application's composer.json is correctly configured as per Composer Configuration for Drupal. It should, at minimum, include the "drupal" repositories entry and installer-paths configuration.

To install a new Drupal project (module, theme, profile, etc.), execute:

$ composer require drupal/[project]

For instance, to require ctools, execute:

$ composer require drupal/ctools

By default this will download the latest stable version. You may also specify the version constraint:

$ composer require drupal/ctools 1.0.0

(See also Specify the Version of a Composer Package.)

This command may return an error if drupal/ctools 1.0.0 or one of its dependencies is not compatible with one of your root dependencies (those explicitly defined in your composer.json file). If that occurs, you will need to change the version constraint for one or more of your requirements until you have defined a set of intercompatible version constraints.

Note that in Composer parlance, "installing" simply means downloading the code, updating composer.lock, and making that code available via the autoloader. You still need to "install" the Drupal project (core, module, theme, profile, etc.) to the Drupal database via the UI or Drush.

Updating a dependency

To update any package, execute:

composer update [vendor]/[package]

For instance, to update drupal/ctools, execute:

$ composer update drupal/ctools

Note that this will update only drupal/ctools and will not update drupal/ctools's dependencies, even if drupal/ctools requires new dependencies.

To update drupal/ctools and also all of the packages that drupal/ctools depends on, execute:

$ composer update drupal/ctools --with-all-dependencies

To update drupal/ctools and require a new minimum version (such as 1.1.0), execute:

$ composer require drupal/ctools:^1.1.0 --update-with-all-dependencies

This command may return an error if drupal/ctools 1.1.0 or one of its dependencies is not compatible with one of your root dependencies (those explicitly defined in your composer.json file). If that occurs, you will need to change the version constraint for one or more of your requirements until you have defined a set of intercompatible version constraints.

To quickly update all packages (within the bounds of your version constraints), execute:

$ composer update

As with updating any Drupal project, you should execute database updates after downloading the new package. If you are using Drupal Configuration Management, you should also re-export configuration after the database updates are complete.

Update Drupal core via Composer

Drupal core is a package like any other. So, you can follow the instructions for "updating a dependency" and simply specify drupal/core as the package name. It's a good idea to specify a new minimum version for drupal/core so that a downgrade is never accidentally performed.

As with updating any Drupal project, you should execute database updates after downloading the new package. If you are using Drupal Configuration Management, you should also re-export configuration after the database updates are complete.

Installing a module's dependencies with Composer

Let's say there's a module we did not install with Composer. How do we install the dependencies listed in that module's composer.json file? If you're asking this question, you're actually on the wrong track. You first must use Composer to manage your entire Drupal application and install the module with Composer. Then, its dependencies will be installed for you automatically. See "Start using Composer to manage an existing Drupal Application" earlier in this tutorial.

As an alternative to using Composer, you might be able to use Ludwig to install the module's dependencies if that module supports Ludwig.

Recap

In this tutorial, we learned how to perform common Composer tasks for Drupal applications.

Further your understanding

  • What does the composer create-project command do?
  • How do you update Drupal core with Composer?
  • How do you install a specific version of a Drupal module?
  • Why might the composer update drupal/ctools:^1.1.0 command fail?

Additional resources