Skip to content

Migration Workflow

The migration workflow is the recommended approach for production environments, team collaboration, and CI/CD pipelines. Every schema change produces a migration file that gets committed to source control, reviewed in a pull request, and applied in sequence.

edit schema → generate → review migration → migrate → check
  1. Edit your schema — modify or create files in schemas/.
  2. Generate a migration — ctkit diffs local vs. remote and produces a timestamped migration file.
  3. Review the migration — inspect the generated file, commit it, open a PR.
  4. Migrate — apply pending migrations to Contentful.
  5. Check — verify local and remote are in sync.

Say you have an existing blogPost schema and want to add a subtitle field:

schemas/blogPost.ts
import { contentType, fields } from '@ctkit/core';
export const blogPost = contentType('blogPost', {
name: 'Blog Post',
fields: {
title: fields.symbol({
name: 'Title',
required: true,
}),
subtitle: fields.symbol({
name: 'Subtitle',
validations: [{ size: { max: 200 } }],
}),
body: fields.richText({
name: 'Body',
}),
publishedAt: fields.date({
name: 'Published At',
}),
},
});
Terminal window
ctkit generate

ctkit connects to Contentful, compares your local schemas against the remote content model, and writes a migration file:

migrations/20250702T143021_crystal_lion_hammer.js

You can also provide a custom name:

Terminal window
ctkit generate --name add-blogpost-subtitle
migrations/20250702T143021_add-blogpost-subtitle.js

Open the generated file and verify the changes look correct. This is the file you commit and push — your teammates review it as part of the PR, just like any other code change.

Terminal window
git add migrations/20250702T143021_add-blogpost-subtitle.js
git commit -m "Add subtitle field to blogPost"
git push

After the PR is merged (or locally during development):

Terminal window
ctkit migrate

This applies all pending migrations in order. You can also preview first:

Terminal window
ctkit migrate --dry-run
Terminal window
ctkit check
✓ Everything is in sync.

If there’s drift between local schemas and the remote model, check will show you exactly what differs.

ScenarioMigration workflow?
Production deploymentsYes
Team collaborationYes
CI/CD pipelinesYes
Auditable change history neededYes
Solo prototyping, throwaway environmentsConsider push instead
  • Reviewable — migration files are plain JavaScript. Teammates can review the exact changes in a PR before they hit Contentful.
  • Reproducible — run the same migrations against staging, then production. Every environment gets the same changes in the same order.
  • Trackable — ctkit records which migrations have run, when, and whether they succeeded. See Migration Tracking for details.
  • Rollback-safe — if a migration fails, ctkit records the failure. You can fix the issue and retry with --force.

A typical CI pipeline looks like:

Terminal window
# In your CI script
ctkit migrate # Apply pending migrations
ctkit check # Fail the build if anything is out of sync

If check exits with a non-zero code, your schemas and Contentful have diverged — the build fails and you know something needs attention.