Migrating an existing Drupal 8 website into a Composer-managed build requires that you build a
composer.json file that includes all of the required packages for your website.
The structure of your repository should shift as follows:
The key differences are the new top-level
composer.lock files, and the top-level location of the vendor directory.
Before you start
It will be easier to compare changes made by Composer if you start with a website that is generally structured the way you want the website to end up.
- Contributed modules - Drupal best practice is to place contributed modules in
docroot/modules/contrib. If your modules are not currently in that path, you should consider moving all contributed modules to
- Custom modules - Drupal best practice is to place custom modules in
docroot/modules/custom. If your modules are not currently in that path, you should consider moving all contributed modules to
- Themes - Drupal best practice is to reflect the same
custom/contribstructure for themes as for modules.
Each one of these changes may require you to run
drush crto ensure your Drupal website knows the new
module/themelocation. It is best that you do this first to reduce potential complications in migrating to Composer.
- Custom code - If you have made any modifications to Drupal core files or contributed module files, you must create patches for them and store them in a top level
patches/directory. Composer update will overwrite all core and contributed module files, but it is able to also apply patches after an update is applied. Creating these patches now will save you trouble later.
If you have modified the Drupal
composer.json file located at
docroot/composer.json, you must note these modifications and prepare to add them to the top-level
composer.json file. This file will be overwritten, and patching it is unnecessary as you can simply add your requirements to the top-level
All of these changes should be committed, tagged, and, if possible, merged to master. This is your new, permanent, file structure.
- Create a development branch that will contain your composer.json file. Do NOT do this on
master. This branch should contain all code required to work on production.
- Obtain a working template for you to use as reference. https://github.com/acquia/acquia-ra-composer/blob/master/composer.json is a great template to use. Save the file at the top level of your repository:
- To simplify the migration, Acquia strongly recommends that you install the exact version of Drupal and all contributed modules that already running on your website. This can be done by pinning your module to a specific version.
To do this, open your
composer.jsonfile, and then edit the
requiresection based on the following notes:
- Drupal core - Require Drupal core by changing
"drupal/core": "^8.3", to your current Drupal version, i.e.,
Specifying the entire version is called “pinning” a package. Pinning has the advantage of ensuring that this and only this version is installed, but it also prevents using the
composer update drupal/core --with-dependenciescommand for updates. This should be unpinned after testing of the Composer migration is complete.
- Contributed modules - All modules that are required to run your website on production should be listed in the
requiresection. Start with contributed modules.
Generate a list of all enabled contributed modules, which you can do with the following Drush command:
drush pml --status=Enabled --no-core
If you are using multisites, evaluate all multisites to ensure that your list is complete. Results should appear similar to the following:
Package Name Type Version
Administration Admin Toolbar (admin_toolbar) Module 8.x-1.19
Chaos tool suite Chaos tools (ctools) Module 8.x-3.0-beta2
Other Pathauto (pathauto) Module 8.x-1.0-rc1
Other Token (token) Module 8.x-1.0-rc1
Other MTM Foundation (mtm_foundation) Theme
Other ZURB Foundation 6 (zurb_foundation)Theme
Each module and theme should be added to the
requiresection. Using the previous example, your
requiresection should appear similar to the following:
- Module paths - Requiring
composer/installersallows you to specify, in the extras section, where composer should download packages of a particular type:
Drupal best practice is to place contributed modules in
docroot/modules/contrib. Your current branch should already reflect the decision you made before you started this process. If your modules are not currently in that path, you will need to modify the installer path by removing
- Libraries - If contrib modules require the manual addition of libraries (in other words, the module does not utilize a
composer.jsonto download its required libraries), you may add them directly to your require section. For an example, see
enyo/dropzonein both the require section as well as the installer-paths section of this sample template: https://github.com/acquia/acquia-ra-composer/blob/master/composer-templates/composer-libraries.json
- Custom modules and themes - There are two ways to handle custom modules and themes:
- Circumvent Composer entirely and directly commit your custom modules and themes to your repository.
- Create them as Composer packages, ensure that they can be downloaded by the Composer, and then include them as you would other packages.
The first is far simpler than the second, but if your theme or module is going to be used by more than one Composer-built website, it may be more efficient and developer-friendly to create your custom code as discrete Composer packages.
In either case, custom code should live in clearly demarcated custom directories:
This allows you to delete the contributed themes and modules by deleting the parent contributed directory entirely, and allow Composer to rebuild it from scratch.
- Drupal core - Require Drupal core by changing
- Delete the following directories (including both the directories' contents and the directories themselves):
- Run the following command:
This should install all the packages required in the
composer.jsonin the proper directory, create a
composer.lockfile, and rewrite
docroot/autoload.phpto point to the new location of the vendor directory (this is what
- Test your now-working website by using
git diffto compare directories or particular files. Compare carefully! If you pinned your modules and core, there should be little difference in module or core files (except
autoload.php). The entire vendor directory has moved, and it is likely that the packages in the vendor directory are different as there may be a more recent version than what is on your current website. This should be fine as the module itself is the same.
Ensure that you verify all parts of your Drupal website, noting if you need to run
drush cr, or if modules appear to be missing.
- Continue to delete, modify the
composer.json, and install until your website is fully working.
- Whenever your website is ready, you should be able to commit the
composer.lock, and all generated code (if you are using CI, this is a different process).
Remember that you are committing ‘pinned’ versions of your modules. This is to ensure that composer is installing the exact versions currently running your website. Your next step, either in this branch or after this branch, has been tested and merged to master, is to change all the versioning in the require section to using the ‘^’ and more open versioning:
At this point, if you were to run
composer update drupal/core --with-dependencies, Composer will update your website to
Drupal 8.3.2 since in this example, we installed
8.3.1. This is what you want, but only after you have tested the migration with pinned versions.