Upgrade from Drupal 8

Upgrade Pantheon Drupal 8 Sites to Drupal 9 With Integrated Composer

Contributors: Dustin LeBlanc, Greg Anderson, Tom Stovall.

Discuss in our Forum Discuss in Slack

This doc shows how to upgrade an existing Pantheon-hosted Drupal 8 site without Composer to a Drupal 9 site with Integrated Composer.

Drupal 9 sites on Pantheon have Composer built-in to manage site dependencies.

The goals of this upgrade are to:

  • remove dependencies that Composer will manage from the existing site's Git repository, and

  • have Composer manage those dependencies in the new site instead.

Note that since you are effectively migrating your site using these upgrade steps, the new site will not maintain your site's existing commit history.

 Multidev Required

To maintain best practice and to avoid difficult, time-consuming repairs to the site, this doc is written for users with access to Pantheon's Multidev feature.

Pantheon support is not available to users who avoid the Multidev steps.

Will This Guide Work for Your Site?

 Do not upgrade unless the site is eligible.

In your site Dashboard, look for the blue banner across the top that says that your site is compatible with a database upgrade:

Good news, your site's database version is now configurable! Learn how.

Contact Support if you're ready to use Drupal 9, but you don't see the banner on the Dashboard.

You might encounter significant issues if the site does not match these requirements.

Before you continue, confirm that your site meets the following:

  • The site has the Pantheon drops-8 repo in its Upstream.

    • The site can not be set to use an empty Upstream.
  • The site does not use a nested docroot.

  • The site does not use Pantheon Search.

  • The site does not use another package and library manager like Ludwig.

Prepare the Local Environment

  1. Review our documentation on Git, Composer, and Terminus, and have them installed and configured on your local computer. Pantheon requires Composer 2 at minimum.

    • Mac users can use Homebrew to install Git, Composer, and PHP 7.4, along with their required dependencies. Restart the shell or terminal environment after entering the following command:

      brew install git composer php@7.4
    • Windows users can install Composer and Git, and may need to install XAMPP or similar to satisfy some dependencies.

  2. Install the Terminus Site Clone plugin.

  3. This guide uses several commands that depend on the site name in the local command line environment.

    To make this easier, set the temporary variable $SITE in your terminal session to match the site name. Read the steps further in this doc to see which sites should be aliased (it may be more than one), then replace anita-drupal in this example:

    export SITE=anita-drupal && echo "New alias set as $SITE"

Apply All Available Upstream Updates

Update the site to the latest Pantheon Drops 8 Upstream and apply all available updates.

  1. Use Terminus to list all available updates:

    terminus upstream:updates:list $SITE
    [warning] There are no available updates for this site.
  2. If any updates are available, apply them using the command line or via the Pantheon Dashboard:

    terminus upstream:updates:apply $SITE.dev --updatedb

Add the Pantheon Integrated Composer Upstream in a New Local Branch

This process involves significant changes to the codebase. We recommend you to do this work on a new branch, as it might take you some time to complete and rolling back changes can be complicated:

  1. In your local terminal, change directories to the site project. For example, if you keep your projects in a folder called projects in the home directory:

    cd ~/projects/$SITE/
  2. Add the Pantheon Drupal Upstream as a new remote called ic, fetch the ic upstream, and checkout to a new local branch based on it called composerify:

    git remote add ic git@github.com:pantheon-upstreams/drupal-project.git && git fetch ic && git checkout --no-track -b composerify ic/master
    Switched to a new branch 'composerify'

    If you prefer, you can replace composerify with another branch name. If you do, remember to adjust the other examples in this doc to match.

  3. Copy any existing configuration from the default branch. If no files are copied through this step, that's ok:

    git checkout master sites/default/config
    git mv sites/default/config/* config
    git rm -f sites/default/config/.htaccess
    git commit -m "Pull in configuration from default branch"
  4. Compare the old codebase's pantheon.yml to the new pantheon.upstream.yml:

    git diff master:pantheon.yml pantheon.upstream.yml

    Press q on your keyboard to exit the diff display.

  5. Copy the old pantheon.yml to preserve settings:

    git checkout master pantheon.yml
    git add pantheon.yml
    git commit -m 'Copy my pantheon.yml'

    Remove any values from pantheon.yml that you prefer to keep as listed in pantheon.upstream.yml.

    Both pantheon.yml and the api_version: 1 value in it are required.

Add in the Custom and Contrib Code Needed to Run Your Site

What makes your site code unique is your selection of contributed modules and themes, and any custom modules or themes your development team has created. These customizations need to be replicated in your new project structure.

Contributed Code

Modules and Themes

The goal of this process is to have Composer manage all the site's contrib modules, contrib themes, core upgrades, and libraries (we'll call this contributed code). The only things that should be migrated from the existing site are custom code, custom themes, and custom modules that are specific to the existing site.

The steps here ensure that any modules and themes from drupal.org are in the composer.json require list.

Once Composer is aware of all the contributed code, you'll be able to run composer upgrade from within the directory to have Composer upgrade all the contributed code automatically.

Begin by reviewing the existing site's code. Check for contributed modules in /modules, /modules/contrib, /sites/all/modules, and /sites/all/modules/contrib.

  1. When reviewing the site, take stock of exactly what versions of modules and themes you depend on. One way to do this is to change to run the pm:projectinfo Drush command from within a contributed modules folder (e.g. /modules, /themes, /themes/contrib, /sites/all/themes, /sites/all/themes/contrib, etc.).

    terminus drush $SITE.dev -- pm:projectinfo --fields=name,version --format=table

    This will list each module followed by the version of that module that is installed.

  2. You can add these modules to your new codebase using Composer by running the following for each module in the $SITE directory:

    composer require drupal/MODULE_NAME:^VERSION

    Where MODULE_NAME is the machine name of the module in question, and VERSION is the version of that module the site is currently using. Composer may pull in a newer version than what you specify, depending upon what versions are available. You can read more about the caret (^) in the Composer documentation.

    Some modules use different version formats.

    • For older-style Drupal version strings:

      Chaos Tools (ctools)  8.x-3.4

      Replace the 8.x- to convert this into ^3.4

    • Semantic Versioning version strings:

      Devel (devel)  4.1.1

      Use the version directly, e.g. ^4.1.1

    If you get the following error, the module listed in the error (or its dependencies) does not meet compatibility requirements:

    Could not find a version of package drupal/MODULE_NAME matching your minimum-stability (stable). Require it with an explicit version constraint allowing its desired stability.

    If there is no stable version you can switch to, you may need to adjust the minimum-stability setting of composer.json to a more relaxed value, such as beta, alpha, or dev (not recommended). You can read more about minimum-stability in the Composer documentation.

    • If a dev version of a module fails because it requires a dev version of a dependency, allowlist the dev dependency in the same composer require as the module:

      composer require drupal/some-module:^1@dev org/some-dependency:^2@dev


Libraries can be handled similarly to modules, but the specifics depend on how your library code was included in the source site. If you're using a library's API, you may have to do additional work to ensure that library functions properly.

Custom Code

Manually copy custom code from the existing site repository to the Composer-managed directory.

Modules and Themes


git checkout master modules/custom
git mv modules/custom web/modules/
git commit -m "Copy custom modules"


git checkout master themes/custom
git mv themes/custom web/themes/
git commit -m "Copy custom themes"

Follow suit with any other custom code you need to carry over.


Your existing site may have customizations to settings.php or other configuration files. Review these carefully and extract relevant changes from these files to copy over. Always review any file paths referenced in the code, as these paths may change in the transition to Composer.

We don't recommend that you completely overwrite the settings.php file with the old one, as it contains customizations for moving the configuration directory you don't want to overwrite, as well as platform-specific customizations.

git status # Ensure working tree is clean
git show master:sites/default/settings.php > web/sites/default/original-settings.php
diff -Nup --ignore-all-space web/sites/default/settings.php web/sites/default/original-settings.php
# edit web/sites/default/settings.php and commit as needed
rm web/sites/default/original-settings.php

The resulting settings.php should have no $databases array.


You've now committed the code to the local branch. Deploy that branch directly to a new Multidev (called composerify in the steps below) and test the site in the browser.

Deploy to a Multidev

  1. Push the changes to a Multidev called composerify to safely test the site without affecting the Dev environment:

    git push -u origin composerify && terminus env:create $SITE.dev composerify
  2. Make a small change to pantheon.yml:

     version: 10.4
    # add a comment to trigger a change and build
  3. Commit and push the change to trigger an Integrated Composer build on the Multidev:

    git commit -am "trigger composer build"
    git push origin composerify

Since the commit history of the composerify Multidev has no commits in common with the master branch, you cannot view the Multidev commit history from the Dashboard or the Integrated Composer logs.

If the site is not working, try this Composer command on the local composerify branch:

composer --no-dev --optimize-autoloader --no-interaction --no-progress --prefer-dist --ansi install

If Composer runs into an error or if any files have been changed (files that are not ignored by .gitignore), resolve those issues before you continue. See the Integrated Composer Troubleshooting section for more information about troubleshooting Integrated Composer.

Move composerify to the Main Dev Branch

Once you have confirmed that the site works in the Multidev, replace the master branch and its commit history with the composerify Multidev's commit history.

  1. Retrieve the most recent commit hash from the local composerify branch:

    git log --format="%H" -n 1

    This will give you a commit hash like fd3636f58f5b275b998bb1c9267bff8808353840.

  2. Reset the master branch to match that commit then force push that to the Dev environment:

    git checkout master
    git reset --hard fd3636f58f5b275b998bb1c9267bff8808353840
    git push --force origin master

Now the site's Dev environment has a Drupal 9 codebase.

Inspect Site Logs to Troubleshoot

If the site doesn't load properly, before you do too much work to investigate issues, clear the cache and try again.

Use Terminus to inspect the site's logs;

terminus drush $SITE.composerify -- wd-show

See our logs collection documentation for more information.

Change Upstreams

Set the site to use the Drupal 9 Upstream:

terminus site:upstream:set $site drupal9

Enter yes when prompted:

Are you sure you want change the upstream for anita-drupal to Drupal 9? (yes/no) [no]:

Note that the User in Charge, Site Owner, or Organization Administrator can change the Upstream.

Ongoing Core Updates

One-click core updates can be made through the Dashboard.

Navigate to Code in the Dev tab of the site's Dashboard. Click Check Now. If updates are available, click Apply Updates.


As packages pulled by Composer are updated (along with their dependencies), version compatibility issues can pop up. Sometimes you may need to manually alter the version constraints on a given package within the require or require-dev section of composer.json in order to update packages. See the updating dependencies section of Composer's documentation for more information.

As a first troubleshooting step, try running composer update to bring composer.lock up to date with the latest available packages (as constrained by the version requirements in composer.json).

See Also