About drupal-migrations
A reference skill for Drupal developers working with migrations. It covers YAML structure, process plugins, custom plugins, and Drush commands for building and troubleshooting migration workflows.
Key features
- 01Migration YAML structure examples
- 02Quick reference for process plugins
- 03Entity references and multi-value handling
- 04Custom source and process plugin examples
- 05Drush migration command reference
Use cases
- 01Writing Drupal migration configuration
- 02Mapping or generating migrated entities
- 03Batch-importing or rolling back with Drush
- 04Checking migration status and row errors
Install
Copy the command and run it in a terminal.
$
npx skills add https:/ / github.com/ edutrul/ drupal-ai --skill drupal-migrationsAfter installing, type/drupal-migrationsin Claude Code to confirm it loaded.
Bundled filesREADME.md
Details
From the project READMEDrupal Migrations
Migration YAML Structure
id: my_migration
label: 'My Migration'
migration_group: my_group # group related migrations together
source:
plugin: source_plugin_name
process:
destination_field: source_field
destination:
plugin: 'entity:node'
default_bundle: article
migration_dependencies:
required:
- other_migration # must match actual migration IDs
Process Plugins Quick Reference
| Plugin | Use for |
|---|---|
default_value | Hardcode a value |
static_map | Map old values → new values |
concat | Join fields with a delimiter |
migration_lookup | Reference a previously migrated entity (by old ID) |
entity_lookup | Reference an existing entity by field value |
entity_generate | Create entity if it doesn't exist |
skip_on_empty | Skip field/row if value is empty |
skip_on_value | Skip row if field equals a value |
sub_process | Iterate a multi-value source array |
Entity References
process:
# Reference a previously migrated entity
uid:
plugin: migration_lookup
migration: users
source: author_id
# Reference an existing entity by field value
field_category:
plugin: entity_lookup
source: category_name
entity_type: taxonomy_term
bundle: categories
bundle_key: vid
value_key: name
# Create term if it doesn't exist
field_tags:
plugin: entity_generate
source: tag_name
entity_type: taxonomy_term
bundle: tags
value_key: name
Multiple Values & Conditional
process:
# Iterate a multi-value source array
field_tags:
plugin: sub_process
source: tags
process:
target_id:
plugin: entity_generate
source: name
entity_type: taxonomy_term
bundle: tags
value_key: name
# Skip field processing if source is empty
field_image:
plugin: skip_on_empty
method: process
source: image_url
# Skip entire row based on a value
pseudo_skip:
plugin: skip_on_value
source: status
method: row
value: 'draft'
Custom Source Plugin
namespace Drupal\my_module\Plugin\migrate\source;
use Drupal\migrate\Attribute\MigrateSource;
use Drupal\migrate\Plugin\migrate\source\SqlBase;
use Drupal\migrate\Row;
#[MigrateSource(id: 'legacy_products', source_module: 'my_module')]
final class LegacyProducts extends SqlBase {
public function query() {
return $this->select('legacy_products', 'p')
->fields('p', ['id', 'name', 'price'])
->condition('p.status', 'active');
}
public function fields() {
return [
'id' => $this->t('Product ID'),
'name' => $this->t('Name'),
'price' => $this->t('Price'),
];
}
public function getIds() {
return ['id' => ['type' => 'integer', 'alias' => 'p']];
}
public function prepareRow(Row $row) {
$row->setSourceProperty('price_with_tax', $row->getSourceProperty('price') * 1.21);
return parent::prepareRow($row);
}
}
Custom Process Plugin
namespace Drupal\my_module\Plugin\migrate\process;
use Drupal\migrate\Attribute\MigrateProcess;
use Drupal\migrate\MigrateExecutableInterface;
use Drupal\migrate\ProcessPluginBase;
use Drupal\migrate\Row;
#[MigrateProcess(id: 'cents_to_decimal')]
final class CentsToDecimal extends ProcessPluginBase {
public function transform($value, MigrateExecutableInterface $migrate_executable, Row $row, $destination_property) {
if (empty($value) || !is_numeric($value)) {
return NULL;
}
return number_format((float) $value / 100, 2, '.', '');
}
}
Key Drush Commands
drush migrate:status # list all migrations + status
drush migrate:import migration_id # run
drush migrate:import migration_id --update # re-run and update existing records
drush migrate:import migration_id --limit=50 # batch to avoid memory issues
drush migrate:rollback migration_id # undo
drush migrate:reset-status migration_id # fix "migration is busy" state
drush migrate:messages migration_id # show per-row errors
Comments
Markdown supported