Laizy CMS
Schema

Migrations

How Laizy schema sync works — migration plans, impact analysis, dry-run mode, and handling destructive changes safely.

Migrations

When you modify your .laizy schema and run laizy sync, the CLI compares your local schema against the current database state and generates a migration plan. This plan describes every change that needs to happen, classifies each by safety level, and asks for confirmation before applying anything destructive.

How Schema Sync Works

The sync process follows a five-step workflow:

Parse Local Schema

The CLI reads your laizy/schema.laizy file and parses it into an AST (Abstract Syntax Tree) containing all your model definitions, fields, and constraints.

Fetch Remote State

The CLI calls the Laizy API to retrieve the current content models stored in the database for your project.

Compute Diff

The Schema Differ compares local models against remote models and produces a diff with three categories:

  • To Create -- Models in your local schema that do not exist in the database
  • To Update -- Models that exist in both but have field or constraint differences
  • To Delete -- Models in the database that are no longer in your local schema

Generate Migration Plan

The Migration Planner takes the diff and produces a plan with operations, impact classifications, and a safety report. Each operation is tagged as safe, warning, or destructive.

Execute or Preview

If --dry-run is set, the CLI displays the plan without executing. Otherwise, it shows the plan and asks for confirmation before applying changes. Content impact analysis enriches the plan with counts of affected entries.

Running Migrations

Preview changes with dry-run

Always preview before applying:

pnpm laizy sync --dry-run

This shows the full migration plan -- which models will be created, updated, or deleted -- without making any changes.

Interactive sync (default)

The standard sync command shows the plan and asks for confirmation:

pnpm laizy sync

For warning and destructive changes, you will see a detailed impact summary and be prompted to confirm. The confirmation message changes based on severity:

  • Warning changes: "Continue with migration?"
  • Destructive changes: "Are you absolutely sure you want to continue? This cannot be undone."

Force sync (skip confirmation)

For CI/CD pipelines or scripts where interactive prompts are not possible:

pnpm laizy sync --force

Using --force skips all confirmation prompts, including for destructive changes. Use this flag carefully and only in automated environments where the migration has already been reviewed.

Impact Classification

Every migration operation is classified into one of three impact levels:

Safe

No data loss or content disruption. These operations execute without requiring confirmation.

OperationExample
Creating a new modelAdding a Product model to your schema
Adding an optional fieldNew subtitle: String field
Adding a field with a defaultNew status: String { default: "draft" }
Relaxing constraintsRemoving required from a field
Changing maxLengthAdjusting character limits

Warning

Changes that may need attention. Existing content might need updates, but data is not lost. Confirmation is required.

OperationExample
Adding a required field without a defaultNew title: String { required: true } on an existing model
Making an optional field requiredChanging from bio: String to bio: String { required: true }
Compatible type changesInt to Float, or String to Int

When a required field is added without a default, the migration planner generates an auto-fill strategy that populates existing entries with a type-appropriate default value:

Field TypeAuto-fill Value
String"" (empty string)
Int0
Float0.0
Booleanfalse
DateTimenull

Destructive

Changes that cause permanent data loss. Strong confirmation is required, and the CLI shows explicit warnings.

OperationExample
Deleting a modelRemoving model Author { ... } from your schema
Removing a fieldDeleting a field from a model
Incompatible type changesBoolean to String, DateTime to Int

Migration Plan Output

When you run laizy sync, the CLI displays a table summarizing each operation:

Migration Plan:

  Operation       Model          Impact        Description
  ────────────    ────────       ──────        ───────────
  create_model    Product        safe          Create new content model "Product" with 4 fields (no existing content)
  update_model    BlogPost       warning       Update model "BlogPost" (2 field changes) (15 content entries affected)
  delete_model    OldPage        destructive   Delete content model "OldPage" and all associated content (3 content entries affected)

The plan includes content impact counts showing how many existing entries will be affected by each change. This helps you understand the scope of the migration before confirming.

Content Impact Analysis

Before executing a migration, the orchestrator queries the API to count how many content entries exist for each affected model. This data enriches the migration plan:

  • No existing content: Changes are effectively risk-free regardless of impact level
  • Content exists: The count is shown alongside each operation so you can assess the real-world impact

For example, deleting a model with 0 entries is technically destructive but practically harmless. Deleting a model with 500 entries deserves careful consideration.

The Schema Sync Pipeline

Under the hood, three components work together:

Schema Differ

Compares local and remote model definitions field by field. For each model that exists in both, it produces a list of FieldChange objects categorized as added, removed, or modified.

Each field change includes:

  • Impact level: safe, warning, or destructive
  • Migration strategy: auto_fill, manual, or none
  • Default value: For auto-fill strategies, the value to use

Migration Planner

Takes the diff and generates an ordered list of MigrationOperation objects. It also produces a SafetyReport summarizing:

  • Count of safe, warning, and destructive operations
  • Warning messages for operations that need attention
  • Whether confirmation is required

Schema Sync Orchestrator

Coordinates the full workflow. It calls the differ, the planner, enriches the plan with content impact data from the API, handles dry-run logic, and executes the migration through the Management Client.

const orchestrator = new SchemaSyncOrchestrator(managementClient);
const result = await orchestrator.syncSchemas(localModels, {
  projectId: 'your-project-id',
  dryRun: false,
  force: false,
});

Migration Strategies

When the planner detects a change that affects existing content, it assigns a migration strategy:

StrategyWhen UsedWhat Happens
auto_fillAdding required field, making field requiredExisting entries are backfilled with a default value
manualIncompatible type changesYou need to manually update data before or after migration
noneSafe changes, optional fieldsNo data transformation needed

Best Practices

  1. Always dry-run first. Run laizy sync --dry-run before every sync to understand what will change.

  2. Add defaults to new required fields. When adding a required field to a model that already has content, include a default value to make the migration safe:

    // Safe migration — default value provided
    category: String {
      required: true
      default: "uncategorized"
    }
  3. Avoid removing fields in production. If you need to deprecate a field, consider making it optional first, then removing it in a later migration after confirming the data is no longer needed.

  4. Use force mode only in CI/CD. The --force flag is designed for automated pipelines where the migration plan has already been reviewed via --dry-run in a previous step.

  5. Check content counts. The migration plan shows how many entries are affected. Zero-content models are safe targets for schema experimentation.

Next Steps

  • Sync Command -- CLI flags and options for the sync command
  • Field Types -- All field types and their migration behaviors
  • Constraints -- How constraints affect migration safety

On this page