Upgrade using Drush

Last updated on
24 October 2023

Drush is a command line shell and scripting interface for Drupal. Upgrading to Drupal 9 or higher using Drush is an alternative to using the browser user interface. Upgrading using Drush is very useful when migrating complex sites as it allows you to run migrations one by one and it allows rollbacks.

Installing Drush with Composer

Drupal 8 or higher sites can be built using Composer. The recommended Composer project doesn't have Drush listed as a dependency, you can install Drush from the command line as follows:

composer require drush/drush

This will give you the latest (stable) Drush which should be compatible with a recent Drupal. For more information about this, read the Drush and Drupal version compatibility matrix

To check your version of Drush, use

drush --version

Required Migration modules

To run the upgrade with Drush you will need these two contrib modules:

  • Migrate Upgrade: Use this module to use migrations as a configuration. This is a common practice but is not required by Drupal core.
  • Migrate Plus: Provides extensions to core migration framework functionality, required by Migrate Upgrade.

 You can download the two modules as follows:

composer require drupal/migrate_upgrade drupal/migrate_plus

Enable the modules:

drush install migrate migrate_drupal migrate_upgrade migrate_plus

Note: Since Drush 10.4, most Migrate Tools commands are included in Drush, except for the migrate:tree command which shows a tree of migration dependencies, which you can get by installing the module. The code-base that made its way into Drush was from an earlier and simpler fork of the Migrate Tools code. For example, Drush does not support migrate plus config entities or provide a progress bar. Over time, the Drush team continues to add features and some of this might become incorporated upstream.

IMPORTANT: Pay close attention to selecting the correct version for each of the three contributed modules. Please refer to the project page for selecting a version compatible with your version of Drupal core.

For more information on the different upgrade modules, please refer to the list of upgrade modules.

Optional migration modules

Visit Drupal 9 (or later) migrate modules for a list of further migration modules.

Define the source database

This is an example of how to define the database connection details for your Drupal 6 / 7 source site. If your source site uses a database prefix, be sure to provide the prefix. You will need to connect to both the local development database (default) as well as the source database (D6 or D7). The following is an example of how to do this with Lando. The example includes the default database set up for completeness.

Note: It is important to name your migrate database key migrate to avoid issues, see Getting 'Field discovery failed for Drupal core version 7.' when migrating.

DDEV: Set up database and source credentials in settings.php

Start up both the source web site (Drupal 7) and target web site (Drupal 10) in separate DDEV instances. Enter the  D7 credentials in the Drupal 10 settings.php, using the Docker containers listed during start up, for example ddev-drupal7-db and ddev-drupal7-web, shown during start up. See Upgrade using web browser > Example values for DDEV for an example.

Lando: Set up database and source credentials in settings.php

$databases['default']['default'] = [
  'database' => 'drupal8',
  'username' => 'drupal8',
  'password' => 'drupal8',
  'prefix' => '',
  'host' => 'database',
  'port' => '3306',
  'namespace' => 'Drupal\\Core\\Database\\Driver\\mysql',
  'driver' => 'mysql',
];

$databases['migrate']['default'] = [
  'database' => 'drupal7db',
  'username' => 'drupal7db',
  'password' => 'drupal7db',
  'prefix' => '',
  'host' => 'd7db',
  'port' => '3306',
  'namespace' => 'Drupal\\Core\\Database\\Driver\\mysql',
  'driver' => 'mysql',
];

Example .lando.yml

name: mywebsite
recipe: drupal8
config:
  webroot: web

# Create Drupal 7 database service, consider adding phpmyadmin
services:
  d7db:
    type: mariadb
    creds:
      user: drupal7db
      password: drupal7db
      database: drupal7db
    portforward: true

Import the Drupal 7 database, assuming the database dump file is called mywebsite_db.sql.gz and in the current folder:

lando db-import --host=d7db --user=drupal7db mywebsite_db.sql.gz

Inspiration from https://github.com/thinktandem/migration_boilerplate.

Generating migrations using migrate:upgrade

Drush adds commands such as drush migrate:status and drush migrate:import. A full list of the migrate-related Drush commands can be found at the bottom of this page. 

If you try drush migrate:status without doing anything else you won't see any migrations available to run. That's because the individual migrations have to first be created based on your source database. Since Migrate has no idea what source to use, no migrations have been created yet. 

To generate the migrations you will need the Drush command drush migrate:upgradewhich is provided by the contributed Migrate Upgrade module.

You most probably want to only generate individual migrations so that you can run them one by one. If this is the case, you need to use the --configure-only option.

The --legacy-db-key option allows you to use a $databases array, with a matching key, defined in settings.php:

drush migrate:upgrade --legacy-db-key=migrate --legacy-root=https://example.com --configure-only 

'https://example.com' is the root of your source site. If the legacy site is on the local filesystem, you can use a file path to the Drupal root directory as the value for this option. The value that you supply here will be prepended to the paths of the individual files to locate and import them.

Use --legacy-db-url for a remote database:

drush migrate:upgrade --legacy-db-url=mysql://user:password@server/db --legacy-root=https://example.com --configure-only 

where

  • 'user' is the username of the source database
  • 'password' is the source database user's password
  • 'server' is the source database server
  • 'db' is the source database

If your source site uses a table prefix in the database table names, you will need to add that as an additional argument as follows. In this example, the database prefix is 'drupal_'

drush migrate:upgrade --legacy-db-url=mysql://user:password@server/db --legacy-db-prefix=drupal_ --legacy-root=https://example.com --configure-only 

If you don't use the --configure-only option, drush migrate:upgradewill first generate and then execute all migrations.

After running migrate:upgrade with the --configure-only parameter, you run migrate:status to see the list of possible migrations:

drush migrate:status 

Then you can review and selectively execute these migrations. To perform the migrations individually run the:

drush migrate:import <migration name> 

There are several Drupal 6 and Drupal 7 migrations that are always created. If you are upgrading from a Drupal 6 site you will see some Drupal 7 migrations when running some drush commands, such as drush migrate:status, and vice versa if you are upgrading from Drupal 7 you will see some Drupal 6 migrations when running some drush command. To avoid seeing those simply use the --tag= option on the drush command:

drush migrate:status --tag='Drupal 7'

To perform all the migrations in the list, run the:

drush migrate:import --all 

To perform only Drupal 7 migrations, run:

drush migrate:import --tag='Drupal 7'

Alternatively, if you followed the guide  Customize migrations when upgrading to Drupal 9 (or later), and created a custom migration module, you can also perform the migration with an additional group annotation:

drush migrate:import --group=your_module --continue-on-failure

This way you only migrate the migrations you defined in your custom migration modules config/install folder.

The --continue-on-failure will additionally prevent your migration from canceling after a failed migration. This way you can do a full migration, check the failed migrations, and implement custom processing for the failed migrations inside your custom module.

Running specific migrations using migrate-manifest

It is also possible to use a manifest file to set up a specific set of migrations. This lets you run groups of migrations in a reproducible manner. For this method, you also need the Migrate Manifest module. With Migrate Manifest, you can get a complete list of available migrations using the following commands:

drush migrate:template:list

The desired migrations are defined as a YAML file as shown in the example below. You only need to list the migrations you need. Migrate Manifest will ask you to add additional migrations that are needed to resolve any dependencies. Migrations can be listed in any order, they will be executed in the correct order based on the dependencies.

# user 
- d6_user 
- d6_user_profile_field 
- d6_user_profile_field_instance 
- d6_user_profile_entity_display 
- d6_user_profile_entity_form_display 
- d6_profile_values:user 
- d6_filter_format 
- d6_user_role 
- d6_user_picture_entity_display 
- d6_user_picture_entity_form_display 
- d6_user_picture_file 
- d6_user_picture_field 
- d6_user_picture_field_instance 

# taxonomy 
- d6_taxonomy_vocabulary 
- d6_taxonomy_settings 
- d6_taxonomy_term 

# nodes 
- d6_node 
- d6_node_revision 
- d6_node_type 
- d6_view_modes 
- d6_filter_format 
- d6_field_instance_per_form_display 
- d6_field_instance_widget_settings 
- d6_field_formatter_settings 
- d6_field_instance 
- d6_field 
- d6_field_settings 
- d6_node_settings 
- d6_cck_field_values:* 
- d6_cck_field_revision:* 

# taxonomy fields 
- d6_term_node_revision 
- d6_term_node 
- d6_vocabulary_entity_display 
- d6_vocabulary_entity_form_display 
- d6_vocabulary_field_instance 
- d6_vocabulary_field 

# blocks 
- d6_block 
- d6_menu 

# custom blocks 
- d6_custom_block 
- d6_filter_format 

# book 
- d6_book 
- d6_book_settings 

# file migrations are configurable, see https://www.drupal.org/node/2257723 
- d6_file: 
    source: 
      conf_path: sites/assets 
    destination: 
      source_base_path: destination/base/path 
      destination_path_property: uri 

Place the manifest file in a location that is accessible when running Drush. Storing it in your version control system is recommended so that you can track changes to your migrations.

Make sure that modules used by the migrations listed in the manifest file exist and are enabled on your source site (e.g. field module for d6_field) Otherwise, there will be errors when the migrations are executed.

The migrations defined in the manifest file are executed from the command line as shown below. Replace the database URL and path to manifest file with appropriate values (like migrate:upgrade, migrate-manifest will accept a MySQL URL or settings.php array key):

drush migrate-manifest --legacy-db-url=mysql://d6user:d6pass@localhost/drupal_6 manifest.yml 

Notes for Acquia Dev Desktop users

If you use Acquia Dev Desktop and have your Drupal 6 site in Dev Desktop, the default database credentials are drupaluser with an empty password and the 33067 port for the database on the 127.0.0.1 IP address. Altogether that leads to --legacy-db-url=mysql://drupaluser:@127.0.0.1:33067/drupal_6 the commands assuming the database name is drupal_6. Run drush status if you are having trouble connecting in order to verify these values.

Reference of Drush migration commands

migrate:upgrade (no alias)

Provided by the Migrate Upgrade project. Use this to run an upgrade from Drupal 6 / 7. This command will generate migration configurations based on the source site's configuration and content. 

Refer to the examples earlier on this documentation page.

Basic example

drush migrate:upgrade --legacy-db-key=migrate

Options

  • legacy-db-url: Database connection information for the source database.
  • legacy-db-prefix: Database table prefix for the source database.
  • legacy-root: Path to the source site, this is used to transfer content from the files directory. If the files are private then a local file path must be specified, for public files http(s) will work as well.
  • configure-only: Use this to create migration configurations only. When this option is set, migrations will be generated so that they can be executed individually with 'drush migrate:import'.

migrate:status (ms)

Included in Drush since 10.4.0. Use this to get the list of all migrations with their current status. Use the --group or --tag option to filter the results.

Basic example

drush migrate:status

migrate:import (mi)

Included in Drush since 10.4.0. Use this to perform one or more migration processes. This is normally used with custom migrations from non-Drupal sources. For example, if you've created and imported a custom migration configuration, this command can be used to run it.

Basic examples

drush migrate:import migration_id
drush migrate:import --tag='Drupal 7'
drush migrate:import --group=files

Options

  • all: Run all migrations currently configured.
  • group: Run all migrations belonging to a particular group.
  • limit: Limit the number of items to process in each migration.
  • feedback: Frequency of progress messages, in items processed.
  • idlist: Comma-separated list of source IDs to import.
  • update: Migrate new items as well as previously migrated items that have been updated on the source.
  • force: Force an operation to run, even if all dependencies are not satisfied.

Common use cases

  • When migrate:upgrade --configure-only is used, configuration entities are created. The default behavior of the new Drupal site is to not allow existing configuration entities to be overwritten, migrate:upgrade cannot be used to run a migration after migrate:upgrade --configure-only is used. Use migrate:import instead.
  • When a custom migration is created and imported (either via the configuration management UI or drush config:import), use migrate:import to run the migration.
  • Use Migrate Devel for troubleshooting errors during import. Example: drush migrate:import migration_id --migrate-debug-pre.

Pro tip: If you've imported a custom migration configuration and you need to update it and re-import it, use the Configuration Update Manager module.

migrate:rollback (mr)

Included in Drush since 10.4.0. Use this to roll back a migration. This is normally used for testing or if you had issues and need to start over. Use this with the id or group of the migration task.

Basic examples

drush migrate:rollback migration_id
drush migrate:rollback --tag='Drupal 7'
drush migrate:rollback --group=files

migrate:stop (mst)

Included in Drush since 10.4.0. Use this to stop an active migration operation.

Basic example

drush migrate:stop migration_id

migrate:reset-status (mrs)

Included in Drush since 10.4.0. Use this to reset an active migration status back to idle.

Basic example

drush migrate:reset-status migration_id

migrate-manifest (no alias)

Provided by the Migrate Manifest module.

migrate:messages (mmsg)

Included in Drush since 10.4.0. Use this to view any messages associated with a migration. This is useful to use when you have a failure in your migration process. This will show you why they failed and what caused them.

Basic example

drush migrate:messages migration_id

migrate:fields-source (mfs)

Included in Drush since 10.4.0. Use this to list the fields available for mapping in a source.

Basic example

drush migrate:fields-source migration_id

migrate:tree (no alias)

Provided by Migrate Tools module, the only command not yet included in Drush. Use this to show a tree of migration dependencies.

Basic example

drush migrate:tree --tag='Drupal 7'

Help improve this page

Page status: No known problems

You can: