The right way to migrate your content using the Contentful Migration CLI

Contentful migration cli

What is the best way to automate your release process? That’s a question that many developers face. Our answer is the Contentful Migration CLI.

With the Contentful Migration CLI, we offer a framework that makes migrations easy and that also makes it possible for developers to script changes to their content model in a fine-grained way. All in the name of making your development process with Contentful as easy as possible.

You can, for example, use this tool together with a continuous integration service, like Travis CI, to run migration scripts on a predefined test space as part of a test suite. This is so that you can validate the deployment before it gets pushed into production.

How the Contentful Migration CLI works

You can use the new Contentful migrations framework for every step of the process: like for creating a new content type, adding a field, or changing validations on a field.

Using JavaScript, you can utilize the Contentful Migration CLI to create migration scripts describing changes to a content model, and then run these scripts on a given Contentful space by using the command line.

Upon execution, the migration CLI does the following:
1. Parses your script
2. Validates your script for syntax or consistency issues
3. Shows you an execution plan, that you then accept if everything looks ok
4. Applies the migration to the space that you specified, once the input has been validated and approved

How to install the Contentful Migration CLI

To install the contentful migration CLI, you need to have Node.js installed, and run the following command:

npm install -g contentful-migration-cli

After the installation is complete, you’ll need to set up and export the following environment variables:

  • CONTENTFUL_MANAGEMENT_ACCESS_TOKEN –– The personal access token for accessing the CMA.
  • HTTP_PROXY or http_proxy (optional) –– The settings for the HTTP proxy in the shape of http://[user:password@]<host>[:port].
  • HTTPS_PROXY or https_proxy (optional) –– The settings for the HTTPS proxy in the shape of https://[user:password@]<host>[:port].

If you have previously installed the Contentful CLI then these will be automatically picked up from your ~/.contentfulrc.json configuration file.

Please note that the environment variables will take precedence over the ~/.contentfulrc.json configuration.

An example of content model migration

Consider the following content model:

1
2
3
4
5
6
7
* Blog post (ID: blogPost)  
  - Title (Symbol)  
  - Body (Text)  
  - Creation date (Date)  
  - Categories (Reference to many category entries)  
* Category (ID: category)  
  - Title (Symbol)  

You can download and import this as an example space by using contentful-import:

1
2
3
4
    contentful-import  
      --space-id $YOUR_SPACE_ID  
      --management-token $CONTENTFUL_MANAGEMENT_ACCESS_TOKEN  
      --content-file migrations-demo-initial-space.json

Imagine an application which uses this data model, and you decide you want to add an Author field — which is defined in a separate content type. The data model, once migrated, will look like so:

1
2
3
4
5
6
7
8
9
10
11
* Blog post (ID: blogPost)
  - Title (Symbol)  
  - Body (Text)  
  - Creation date (Date)  
  - Categories (Reference to many category entries)  
  - Author (Reference to one author)  
* Category (ID: category)  
  - Title (Symbol)  
* Author (ID: author)
  - Full name (Symbol)  
  - Twitter (Symbol)  

So let’s say we create a migration script called 01-add-author.js with the following content:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
module.exports = function(migration) {
  const author = migration.createContentType('author')
  author
    .name('Author')
    .description('Author of a blog post')
    
  author
    .createField('fullName')
    .name('Full name')
    .type('Symbol')
    .required(true)
    
  author
    .createField('twitter')
    .name('Twitter')
    .type('Symbol')
    .validations([
      { "unique": true },
      { "regexp": 
        { "pattern": "^\\w[\\w.-]*@([\\w-]+\\.)+[\\w-]+$" }
      }
    ])
    
  const blogPost = migration.editContentType('blogPost')
  blogPost.createField('author')
    .name('Author')
    .type('Link')
    .linkType('Entry')
    .validations([
      { "linkContentType": ["author"] }
    ])
};

For more information about the available functions, see the contentful-migration reference documentation.

We then kick off the migration:

contentful-migration --space-id $YOUR_SPACE_ID 01-add-author.js

What we will then see is the following migration plan:

Contentful migrations – Blog post proposal - Plan

Since everything looks the way we want it to, we’ll go ahead with the migration:

Contentful migrations – Blog post proposal - Result

How to validate migrations

In order to prevent as many errors as possible, the migration executor performs some sanity checks on migration files. The sanity checks include:

  • Syntax: typos, invalid properties, wrong types
  • Consistency: create a content type or field that already exists, delete a field or edit a content type that doesn’t exist, etc.

All types of validation errors are listed in the reference documentation.

Whenever a validation issue is detected, the contentful-migration command displays details of the error, including the line number within the script where the problem originates from:

Validation failed

What’s next

The Contentful Migration CLI is still in its early stages. And we will expand the framework in the near future to also cover content transformation, and integrate it in our main CLI.

We’re always keen to get your feedback, so feel free to reach out if you have ideas, remarks or if you are experiencing issues. You can connect with us via our Slack community channel at contentful.com/slack or by writing to devrel@contentful.com.

Blog posts in your inbox

Subscribe to receive most important updates. We send emails once a month.