Craft News

Coming to Craft 3: Content Migrations

Sep 21, 2016 in Announcements

One of the biggest pain points of working with Craft (and most database-driven CMSes) is replicating changes across multiple environments. Whether you’re building a new site with a colleague, or maintaining an existing site with dev and production environments, when a change is made in one place, there’s no straightforward way to replicate the change elsewhere.

That’s going to get a little better in Craft 3, thanks to Content Migrations.

If you’ve written a plugin for Craft, you may already be familiar with the concept of migrations. They are PHP classes that make some sort of change to the Craft install (usually in the database). Many Craft and plugin updates will come with one or more new migration files, to reflect any new changes to the DB schema.

Content Migrations are just like normal Craft/plugin migrations, except that they’re intended to help define changes to content, rather than the application’s or a plugin’s DB schema.

To create a new content migration, create a new migrations/ folder within your craft/ folder, then open your Terminal and run these commands:

> cd path/to/craft/app
> chmod +x craft
> ./craft migrate/create my_migration_name

Enter yes at the prompt, and then a new migration file will be created for you in your new craft/migrations/ folder. Open it and edit its safeUp() function to define the changes that should be made. For example, if you wanted to create a new section, your safeUp() function would look something like this:

public function safeUp()
    // Get the primary site ID
    $siteId = Craft::$app->sites->getPrimarySite()->id;

    // Create a model of the new section
    $section = new \craft\app\models\Section([
        'name' => 'Awesome News',
        'handle' => 'awesomeNews',
        'type' => 'channel',
        'siteSettings' => [
            $siteId => new \craft\app\models\Section_SiteSettings([
                'hasUrls' => true,
                'uriFormat' => 'awesome-news/{slug}',
                'template' => 'awesome-news/_entry',

    // Save it
    $success = Craft::$app->sections->saveSection($section);

    return $success;

You can also optionally fill in the safeDown() function, which is used to revert the migration:

public function safeDown()
    // Get the section
    $section = Craft::$app->sections->getSectionByHandle('awesomeNews');

    // Delete it
    $success = Craft::$app->sections->deleteSectionById($section->id);

    return $success;

To run your new migration, use the migrate/up command:

> ./craft migrate/up

Enter yes at the prompt, and your new migration will get executed.

After you’ve created a migration, you can commit it to your version control system and deploy it to the other environments, right along with other file-based changes like templates and front-end resources. Note that Craft will not automatically check for new content migrations, so you will need to manually run the migrate/up command on each individual environment.

To read more about migrations, and what migrate commands are available, see Yii’s documentation.

This is, admittedly, not a complete solution to Craft’s content replication problem—it’s only going to work for people that are comfortable with PHP, Yii, and Craft’s APIs, plus SSH access for remote environments—but it’s a step in the right direction. And we’re committed to making it better as time goes on.

Content Migrations are available now, in the latest release of the Craft 3 Dev Preview. Check it out and let us know what you think!