Migrations
Vortex provides optional support for a second database to power Drupal
migrations. When enabled, a database2 Docker service runs alongside the
primary database, and a settings.migration.php file registers the
$databases['migrate'] connection that Drupal's Migrate API uses by default.
Enabling the migration database
Via the installer
When running the Vortex installer, answer Yes to "Use a second database for migrations?" and select a fetch source.
Manual setup
If you already have a Vortex project and want to add migration support:
- Ensure
docker-compose.ymlcontains thedatabase2service andDATABASE2_*environment variables (copy from a fresh Vortex install with migration enabled). - Add
VORTEX_FETCH_DB2_FILE,VORTEX_FETCH_DB2_SOURCE, andVORTEX_FETCH_DB2_URLto.env. - Create
web/sites/default/settings.migration.php(see below). - Add the include in
web/sites/default/settings.php. - Add
scripts/provision-20-migration.sh.
Environment variables
| Variable | Default | Description |
|---|---|---|
VORTEX_FETCH_DB2_FILE | db2.sql | Migration database dump file name |
VORTEX_FETCH_DB2_SOURCE | url | Fetch source (url, ftp, acquia, lagoon, s3) |
VORTEX_FETCH_DB2_URL | (empty) | URL to fetch the migration database dump |
DATABASE2_HOST | database2 | Migration database host |
DATABASE2_NAME | drupal | Migration database name |
DATABASE2_USERNAME | drupal | Migration database user |
DATABASE2_PASSWORD | drupal | Migration database password |
DATABASE2_PORT | 3306 | Migration database port |
Docker service
The database2 service uses the same Lagoon database image as the primary
database, and the image can be overridden with the VORTEX_DB2_IMAGE variable
(for example, to use a database-in-image seed):
database2:
image: "${VORTEX_DB2_IMAGE:-uselagoon/mysql-8.4:26.8.0}"
environment:
<<: *default-environment
MYSQL_DATABASE: drupal
MYSQL_USER: drupal
MYSQL_PASSWORD: drupal
ports:
- '3306'
labels:
lagoon.type: mariadb
The image tag tracks the primary database image - check the shipped
docker-compose.yml
for the current version.
Drupal settings
settings.migration.php
<?php
/**
* @file
* Migration settings.
*
* @todo Migration. Remove when migration configuration is no longer required.
*/
declare(strict_types=1);
// Migration DB settings.
$databases['migrate']['default'] = [
'database' => (getenv('DATABASE2_NAME') ?: getenv('DATABASE2_DATABASE')) ?: 'drupal',
'username' => getenv('DATABASE2_USERNAME') ?: 'drupal',
'password' => getenv('DATABASE2_PASSWORD') ?: 'drupal',
'host' => getenv('DATABASE2_HOST') ?: 'localhost',
'port' => getenv('DATABASE2_PORT') ?: '',
'prefix' => '',
'driver' => 'mysql',
];
Drupal's Migrate API SqlBase source plugin uses key: migrate by default,
which resolves to this connection.
Ahoy commands
| Command | Description |
|---|---|
ahoy fetch-db2 | Fetch the migration database dump |
ahoy fetch-db2 --fresh | Force a fresh fetch |
ahoy reload-db2 | Recreate the database2 container and re-import its dump |
ahoy db2 | Open the migration database in Sequel Ace |
The fetch-db2 command reuses the existing vendor/bin/vortex-fetch-db
tooling script with VORTEX_DB_INDEX=2, which makes all scripts resolve
indexed variable names (e.g., VORTEX_FETCH_DB2_SOURCE instead of
VORTEX_FETCH_DB_SOURCE, VORTEX_DB2_IMAGE instead of VORTEX_DB_IMAGE) so
all existing fetch sources (URL, FTP, Acquia, Lagoon, S3) work for the
migration database as well.
Provision script
The scripts/provision-20-migration.sh script runs automatically
during ahoy provision (custom provision scripts are executed alphabetically).
It handles:
- Importing the migration source database dump into the
database2container - Corruption detection (probes for a known table to verify the database)
- Running Drupal migrations via
drush migrate:import - Optional rollback before import
- Disabling the Solr search server while the migrations run
On projects with the Solr service, the script disables the search server before
the migrations and enables it again afterward, so migrated entities are not
indexed one at a time. The scripts/provision-30-search-index.sh script rebuilds
the index straight after.
Set DRUPAL_MIGRATION_SEARCH_DISABLE=0 to leave the search server running and
index entities as they are migrated.
Configuration variables
| Variable | Default | Description |
|---|---|---|
DRUPAL_MIGRATION_SKIP | 0 | Skip all migration operations |
DRUPAL_MIGRATION_ROLLBACK_SKIP | 1 | Skip rollback before import |
DRUPAL_MIGRATION_IMPORT_LIMIT | 50 | Limit entities per migration (use all for unlimited) |
DRUPAL_MIGRATION_UPDATE | 0 | Update already imported entities |
DRUPAL_MIGRATION_FEEDBACK | 50 | Progress feedback frequency |
DRUPAL_MIGRATION_SOURCE_DB_IMPORT | $VORTEX_PROVISION_OVERRIDE_DB | Import source database (1 to import, 0 to skip) |
DRUPAL_MIGRATION_SOURCE_DB_PROBE_TABLE | categories | Table name to probe for corruption detection |
DRUPAL_MIGRATION_SEARCH_DISABLE | 1 | Disable the Solr search server while migrations run (0 to keep indexing) |
Adding migrations
Add your project-specific migrations at the bottom of the script using the
run_migration helper:
run_migration my_migration
The per-migration entity limit comes from DRUPAL_MIGRATION_IMPORT_LIMIT
(set it to all for unlimited), and progress feedback from
DRUPAL_MIGRATION_FEEDBACK.
Corruption detection
If DRUPAL_MIGRATION_SOURCE_DB_IMPORT is 0, the script probes the source database
for the table specified in DRUPAL_MIGRATION_SOURCE_DB_PROBE_TABLE. If the table is
missing (corrupted or empty database), the script automatically re-imports the
dump file.
Demo migration module
Vortex ships with a demo migration module ys_migrate in
web/modules/custom/ys_migrate/. It demonstrates the full migration workflow
by migrating categories from the source database into Drupal's tags
taxonomy vocabulary.
Migration: ys_migrate_categories
| Property | Value |
|---|---|
| Source plugin | ys_migrate_categories (reads from categories table) |
| Source key | migrate (the $databases['migrate'] connection) |
| Destination | entity:taxonomy_term |
| Vocabulary | tags |
The migration maps:
name→ term namedescription→ term description (plain text format)
Dependencies
The module requires drupal/migrate_plus and drupal/migrate_tools (added
to composer.json when the migration feature is enabled).
CI integration
Both CI systems (GitHub Actions and CircleCI) include a migration database
fetch step in the existing database job. Both database files are cached
together in the same .data directory.
The build job copies the migration database file into the CLI container
alongside the primary database before running provision.
Example workflow
-
Set
VORTEX_FETCH_DB2_URLin.env(or.env.local):VORTEX_FETCH_DB2_URL=https://example.com/legacy-database.sql -
Fetch the migration database:
ahoy fetch-db2 -
Build and provision:
ahoy build -
Add your migrations to
scripts/provision-20-migration.sh:run_migration my_migration -
Re-provision to run migrations:
ahoy provision
➡️ See Provision for how the custom provision scripts run, and Contributed modules for the shipped migration modules.