Skip to main content
As your content model evolves, some changes require explicit migration steps. This page explains when migrations are needed, how the database schema is managed, and how content migrations transform existing documents.

When Migrations Are Needed

Not every schema change requires a migration. MDCMS distinguishes between non-breaking changes (handled automatically) and breaking changes (requiring explicit migration).

Non-Breaking Changes

For non-breaking changes, the standard schema sync workflow handles everything automatically:
1

Update the schema

Modify your mdcms.config.ts to add the new field, type, or environment.
2

Sync to the server

Run mdcms schema sync. The server computes the new schema hash and updates the schemaRegistryEntries and schemaSyncs tables.
3

Continue editing

Existing documents remain valid. New documents will include the updated field definitions in the Studio editor.
Schema sync is idempotent. Running it multiple times with the same configuration produces the same result. It is safe to include in CI/CD pipelines.

Database Migrations

Database schema changes (adding tables, columns, or indexes to the PostgreSQL schema) are managed through Drizzle ORM’s migration toolkit.
1

Modify the schema definition

Edit apps/server/src/lib/db/schema.ts to add, modify, or remove table definitions.
2

Generate the migration SQL

Run the Drizzle migration generator: bash cd apps/server bun run db:generate This produces a timestamped SQL migration file in the migrations directory.
3

Review the generated SQL

Always review the generated migration before applying it. Drizzle generates SQL based on the diff between the current schema definition and the last known state. Verify that destructive operations (column drops, type changes) are intentional.
4

Apply the migration

Run the migration against the target database: bash cd apps/server bun run db:migrate
Always back up the database before applying migrations in production. Drizzle migrations are forward-only — there is no automatic rollback mechanism.

Content Migrations

Content migrations transform existing documents when the schema changes in a way that is incompatible with stored data. The mdcms migrate CLI command handles this process.

Preview Mode

By default, mdcms migrate generates a migration plan without applying it:
This analyzes the current schema against stored documents and reports:
  • Which documents are affected
  • What transformations will be applied
  • Whether any documents cannot be automatically migrated

Apply Mode

To execute the migration, add the --apply flag:
When applied, the migration:
  1. Transforms each affected document’s frontmatter according to the migration rules
  2. Updates the draft state (body, frontmatter, updatedAt, draftRevision)
  3. Auto-publishes updated documents that were previously in a published state
  4. Records the migration in the migrations table (name, schema type, documents affected, who applied it, when)
Always back up the database before running content migrations in production. Content migrations modify document frontmatter in place and auto-publish affected documents. While the operation is logged in the migrations table, there is no built-in undo mechanism.

Breaking Change Scenarios

The following scenarios require explicit content migrations.

Type Rename

When renaming a content type (e.g., Post to BlogPost):
  1. Add the new type to mdcms.config.ts
  2. Run mdcms schema sync to register the new type
  3. Run mdcms migrate --apply to update all documents from the old type to the new type
  4. Remove the old type from the config
  5. Run mdcms schema sync again to deregister the old type

Field Type Change

When changing a field’s type (e.g., tags: z.string() to tags: z.array(z.string())):
  1. Update the field definition in mdcms.config.ts
  2. Run mdcms schema sync
  3. Run mdcms migrate to preview the transformation (e.g., wrapping string values in arrays)
  4. Run mdcms migrate --apply to execute

Field Removal

When removing a field from a content type:
  1. Remove the field from mdcms.config.ts
  2. Run mdcms schema sync
  3. Run mdcms migrate --apply to clean the removed field from existing document frontmatter
Field removal migrations are optional but recommended. Documents with extra frontmatter fields will not cause errors, but removing stale data keeps the content store clean and reduces confusion in API responses.

Migration Records

Every applied migration is recorded in the migrations table: This table provides an audit trail for all content transformations and can be queried to verify migration history.