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.
How it works
Section titled “How it works”edit schema → generate → review migration → migrate → check- Edit your schema — modify or create files in
schemas/. - Generate a migration — ctkit diffs local vs. remote and produces a timestamped migration file.
- Review the migration — inspect the generated file, commit it, open a PR.
- Migrate — apply pending migrations to Contentful.
- Check — verify local and remote are in sync.
Step by step
Section titled “Step by step”1. Edit your schema
Section titled “1. Edit your schema”Say you have an existing blogPost schema and want to add a subtitle field:
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', }), },});2. Generate a migration
Section titled “2. Generate a migration”ctkit generatectkit connects to Contentful, compares your local schemas against the remote content model, and writes a migration file:
migrations/20250702T143021_crystal_lion_hammer.jsYou can also provide a custom name:
ctkit generate --name add-blogpost-subtitlemigrations/20250702T143021_add-blogpost-subtitle.js3. Review the migration
Section titled “3. Review the migration”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.
git add migrations/20250702T143021_add-blogpost-subtitle.jsgit commit -m "Add subtitle field to blogPost"git push4. Apply the migration
Section titled “4. Apply the migration”After the PR is merged (or locally during development):
ctkit migrateThis applies all pending migrations in order. You can also preview first:
ctkit migrate --dry-run5. Verify everything is in sync
Section titled “5. Verify everything is in sync”ctkit check✓ Everything is in sync.If there’s drift between local schemas and the remote model, check will show you exactly what differs.
When to use this workflow
Section titled “When to use this workflow”| Scenario | Migration workflow? |
|---|---|
| Production deployments | Yes |
| Team collaboration | Yes |
| CI/CD pipelines | Yes |
| Auditable change history needed | Yes |
| Solo prototyping, throwaway environments | Consider push instead |
Why migrations matter
Section titled “Why migrations matter”- 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.
CI/CD integration
Section titled “CI/CD integration”A typical CI pipeline looks like:
# In your CI scriptctkit migrate # Apply pending migrationsctkit check # Fail the build if anything is out of syncIf check exits with a non-zero code, your schemas and Contentful have diverged — the build fails and you know something needs attention.