One of the big features for craft 3 is content migrations. Migrating fields and sections between environments (like deploying code to test or production). I'm just having a hard time figuring out what options there are. I did find some simple examples, but they are a little limited...

https://craftcms.com/news/craft-3-content-migrations https://docs.craftcms.com/v3/content-migrations.html

Since there is a separate documentation page which seems incomplete i created an issue. If anyone has some additional info i would like to make a pull-request to complete the docs.


5 Answers 5


For now (when the docs are not ready) you look into the craft source how things are saved for example:


Based on the source code I've created the following migration file:


  • Thanks, that's what i was trying to do for now. It just involves a lot of searching in the code. Seems like this would be a good addition to the docs.
    – Roel
    Sep 5, 2017 at 8:13
  • The migration docs are still not updated for craft3. I think github.com/pennebaker/craft-architect is a nice plugin to use for migrations, it saves a lot of time coding them yourself. If you want to write custom migrations the source of that plugin can be helpful.
    – Jeroen
    Feb 16, 2018 at 16:36
  • For Craft 2 i'm using Schematic, Architect looks similar to that. The major issue with having a complete layout of the structure is that changes are missing. For example, when you rename something, it won't rename on execution. The old field or section wil be removed and a new one created, which results in data loss. Be aware of this. This is why i'm starting to like the migrations written in separate php classes, you can rename things without much of an issue.
    – Roel
    Feb 17, 2018 at 20:09
  • Good point to be aware of. I think writing migrations by hand can get compicated with fields like matrix or something like super-table (plugin). I have done lots of sites with Wordpress ACF and love how they keep in sync of the custom fields with the json files. But you also have to migrate the content when renaming fields. Migrations by hand give you more possibilities to do this and you have a better history in git than json files although they cost more developer time.
    – Jeroen
    Mar 17, 2018 at 19:10

This is a plugin I'm working on to do exactly what you are after.


The syntax to figure out how to create sections, elements etc is determined by reading through the craft service and model classes.

  • This looks awesome. How is the progress on the plugin? Is this going to be an open-source kind of thing?
    – Roel
    Jul 18, 2017 at 11:35
  • Thanks. Hoping to have a beta release in the next month. It will be open source. Jul 19, 2017 at 12:49

"I'm just having a hard time figuring out what options there are."

The options are virtually limitless. You can put almost anything you want into a safeUp method.

Craft 3 is still in beta, and probably will be for another six months or so. They are likely to expand on the current docs for migrations, but I wouldn't expect to see that until much closer to the official release.

  • Sorry, i should have been clearer there. I meant the options regarding the creation/modification/removal of fields, sections, entryTypes, globals etc. Right now i'm using github.com/nerds-and-company/schematic to handle this in Craft 2. Renaming and removal is problematic, which should be no problem for migrations.
    – Roel
    Apr 4, 2017 at 12:15
  • It's not a fixed set of options... it's more like a blank canvas. You can do literally anything you want in a migration.
    – Lindsey D
    Apr 4, 2017 at 18:12
  • I think Roel is asking for an example of the syntax required to create a new section, with a set of custom fields. As in, what would the code look like to achieve this.
    – SteveEdson
    Jun 19, 2017 at 17:30

I've written up an article with some basic examples of content migrations in Craft 3: https://medium.com/@mikethehud/craft-cms-3-content-migration-examples-3a377f6420c3

As others have stated I just read through the code base / api docs (https://docs.craftcms.com/api/v3/) to find out what methods and services to use to save specific things.

Hope that helps!

  • Thanks, i did see that article yesterday and it really helped! I think i saw it at Craft's twitter.
    – Roel
    Jul 24, 2018 at 6:03

I did some initial attempts, and this is what I cooked up (only the safeUp() method).

It is probably not the best way to do this, but the way I've so far found.

Currently it creates a field group myFieldGroup with a field fieldName of type Plaintext.

As others have said, you can do virtually anything with migrations, all it takes is figuring out how.

public function safeUp()

    $fieldGroupName = 'myFieldGroup';
    $fieldService = Craft::$app->getFields();
    $fieldGroup = new FieldGroup();

    $fieldGroup->name = $fieldGroupName;

    $fieldGroupSuccess = $fieldService->saveGroup($fieldGroup);

    if ($fieldGroupSuccess) {
        $fieldGroupId = null;

        // FIXME: Couldn't find a method to search for a field group by name
        $fieldGroups = $fieldService->getAllGroups();
        foreach ($fieldGroups as $group) {
            if ($group->name == $fieldGroupName) {
                $fieldGroupId = $group->id;
        if (!$fieldGroupId) {
            echo "Couldn't find ID for field group, aborting";
            return false;
        $field = $fieldService->createField([
            'type' => 'craft\fields\PlainText',
            'groupId' => $fieldGroupId,
            'name' => 'fieldName',
            'handle' => 'fieldNameHandle'
    return $fieldService->saveField($field);
  • You know Craft attaches the id to your $fieldGroup variable inside the save method? That said doing $fieldGroupId = $fieldGroup->id is totally enough. More important you should check if the $field variable actually exists, if someone copies your code and inserts something strange as a field name and the validation fails your $field variable is not initialized and it will trow an exception github.com/craftcms/cms/blob/develop/src/services/… Jan 9, 2018 at 7:29
  • After some research, i figured out the migrations from the controllers. I still need to do a pull-request to the docs to help others. I did the same thing @user2874204 suggested.
    – Roel
    Jan 10, 2018 at 9:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.