Updating existing content rather than importing new content - system-of-record

Last updated on
30 April 2025

While the Migrate module was originally developed for the purpose of performing complete site migrations, where the source data is always the system of record, it can be used for other scenarios. For example, you might define a migration process for the purpose of updating only specific fields on existing content with new data, or after initially performing a full migration of new content you might want to remigrate the legacy data while preserving some changes you've made on the destination side. To control this behavior, the Migration class supports setting the system of record for the migration.

  /**
   * Indicate whether the primary system of record for this migration is the
   * source, or the destination (Drupal). In the source case, migration of
   * an existing object will completely replace the Drupal object with data from
   * the source side. In the destination case, the existing Drupal object will
   * be loaded, then changes from the source applied; also, rollback will not be
   * supported.
   *
   * @var int
   */
  const SOURCE = 1;
  const DESTINATION = 2;
  protected $systemOfRecord = Migration::SOURCE;

So, by default the system of record is the source data - if you remigrate existing data (e.g., with --update on your drush migrate-import command), the Drupal content is completely replaced by the content from the source. However, in the constructor for your migration you can set

  $this->systemOfRecord = Migration::DESTINATION;

If you do this, then when you run drush migrate-import only the fields that you have mapped in the migration will be replaced on the Drupal side - all other fields will retain their existing values.

So, when you are defining a migration whose purpose is updating existing content, just set systemOfRecord and add field mappings for the specific fields you want to update, leaving the rest unmapped. Of course, there is another way to circumvent changing the entire systemOfRecord and still protecting a few fields. Described in a protecting migration fields on update cookbook example.

If you are updating content from a previous migration you must map the NID to the primary key it relates to and tell Migrate what the initial migration was called so it knows what node to update.

$this->addFieldMapping('nid', 'key')
         ->sourceMigration('Beer');

If you'd like to run an initial migration to create content from an external source, and also be able to run subsequent migrations that update existing content but preserve some Drupal-side changes, you need to define separate Migration classes for the latter purpose with systemOfRecord set to Migration::DESTINATION.

Help improve this page

Page status: Not set

You can: