Skip to main content

Content Migrations in Contember

Introduction​

Content migrations within Contember are designed to manage and transform the existing data in your database. This is achieved using GraphQL queries, which provide a powerful and versatile approach to data manipulation.

Setting Up Content Migration Files​

Content migration files should be added to the api/migrations directory in your Contember project. The naming convention for these files is YYYY-MM-DD-HHMMSS-label, which ensures they are executed in the correct order and are easy to identify.

Example File Name: 2023-10-26-150000-add-english-locale.js

Using the CLI to create blank migration files​

You can use the Contember CLI to create blank migration files. Simply run the following command and provide a label for your migration.

yarn contember migration:blank <label>

Depending on the complexity of your migration, you can choose to use a JSON, JavaScript (JS), or TypeScript (TS) file. By default, the CLI will create a TypeScript file.

Defining Migrations in JSON​

Content migrations can be defined in JSON, using a single "query" or an array of "queries".

Single Query Example​

{
"query": "mutation { createLocale(data: { code: \"en\" }) { ok errorMessage } }"
}

Multiple Queries Example​

{
"queries": [
{
"query": "mutation { createLocale(data: { code: \"en\" }) { ok errorMessage } }"
},
{
"query": "mutation { createLocale(data: { code: \"fr\" }) { ok errorMessage } }"
}
]
}

Defining Migrations in JavaScript or TypeScript​

For more advanced use cases, JS or TS can be used to define migrations.

Single Query with Variables​

export default {
query: `
mutation CreateLocale($data: LocaleCreateInput) {
createLocale(data: $data) {
ok
errorMessage
}
}
`,
variables: {
data: {
code: "en"
}
}
};

Multiple Queries with Variables​

export default {
queries: [
{
query: `
mutation CreateLocale($data: LocaleCreateInput) {
createLocale(data: $data) {
ok
errorMessage
}
}
`,
variables: {
data: {
code: "en"
}
}
},
{
// Second query
}
]
};
Using named exports

Instead of default export, you can use named exports "queries" and "query" to define migrations.

Utilizing Functions in Migrations​

Functions in migration files provide a higher level of control and the ability to perform dynamic operations.

export default async function () {
// Fetch data, execute queries, and perform other asynchronous operations here.

// Return content migrations if needed
return {
queries: [
// Individual queries
]
};
};

Validating Mutation Results​

It's crucial to fetch the "ok" and "errorMessage" fields for top-level mutations to ensure they have executed successfully. Contember CLI checks these fields by default, but you can bypass this check (not recommended) by including checkMutationResult: false in your query object.

Applying Migrations​

To run your content migrations, use the Contember CLI’s migration:execute command.

npx contember migration:execute

Execution Model for Function Migrations​

Function migrations introduce a unique execution model. The CLI orchestrates the migrations, grouping non-function migrations into a single transaction, while function migrations are executed separately, each in its own transaction.

Execution Flow Example:

  • Transaction 1:

    • Schema Migration A
    • Content Migration B
    • Schema Migration C
  • Function Migration (Separate Transaction):

    • Execute exported function and await result
    • If the function returns content migrations, send them to the migration API
  • Subsequent Non-Function Migrations (New Transaction)

Note: Due to this model, it’s advisable to run function migrations independently to avoid complications, as some migrations might succeed even if others fail.