Migrations Guide

Preview feature: CLI AI Automation is a preview feature. If you encounter any issues, please report them at support.skipper18.com.

Skipper CLI provides full support for creating and managing database migrations from the command line. This guide explains how to use CLI verbs to create migrations, automate export workflows, and integrate migration generation into your development process.

What Are Migrations?

Migrations are incremental scripts that transform your database schema from one version to the next. Instead of manually writing ALTER TABLE statements, Skipper tracks changes you make to your model and generates the corresponding migration files for your ORM framework.

When you add a new entity, rename a field, or change an association in Skipper, those changes are recorded. The next time you create a migration, Skipper compares the current model state to the last known state and generates only the necessary migration code.

Skipper supports migrations for frameworks that have built-in migration support, such as Doctrine 2, Laravel Eloquent, and others. The generated migration format matches what each framework expects, so the files work directly with your existing migration tooling.

Creating Migrations via CLI

Use the -cli-create-migration verb to generate a new migration revision from pending schema changes.

Skipper.exe -cli-create-migration project.skipper -quiet

If there are pending changes, Skipper creates a new migration revision and returns a success envelope:

{
  "status": "ok",
  "data": {
    "created": true
  }
}

If there are no pending changes, the command still succeeds but indicates that no migration was needed:

{
  "status": "ok",
  "data": {
    "created": false,
    "reason": "no_changes_pending"
  }
}

If migrations are not enabled for the project's framework, you will receive a MIGRATIONS_DISABLED error. Make sure your project is configured with a framework that supports migrations.

Export Workflow

The typical migration workflow has three steps: validate the schema for errors, create a new migration from pending changes, and export all code (including migrations). Here are the commands to run in sequence:

Step 1 — Validate the schema:

Skipper.exe -cli-validate project.skipper -quiet

Step 2 — Create a migration from pending changes:

Skipper.exe -cli-create-migration project.skipper -quiet

Step 3 — Export all code (classes and migrations):

Skipper.exe -cli-export project.skipper -quiet

After export, the generated migration files will be written to the output directory configured in your project. Check the export envelope's files_written array to see exactly which files were created.

Database Import and Modify

A powerful workflow is to reverse-engineer a Skipper project from an existing database, apply modifications via CLI patches, and then create migrations for those changes. This lets you work with a live database as your starting point.

Step 1 — Import the database into a Skipper project:

Skipper.exe -cli-import-database \
  -output project.skipper \
  -db-class mysql \
  -connection "host=localhost;port=3306;dbname=myapp;user=root;password=secret" \
  -orm doctrine2 \
  -mvc symfony \
  -skip-initial-migrations \
  -quiet

Step 2 — Apply schema modifications with a patch:

# Create a patch file with desired changes
cat > changes.json << 'EOF'
[
  {"op": "add_entity", "args": {"module": "default", "name": "AuditLog"}},
  {"op": "add_field", "args": {"entity": "AuditLog", "name": "id", "type": "integer", "primary": true, "auto_increment": true}},
  {"op": "add_field", "args": {"entity": "AuditLog", "name": "action", "type": "string", "size": 255}},
  {"op": "add_field", "args": {"entity": "AuditLog", "name": "createdAt", "type": "datetime"}},
  {"op": "add_association", "args": {"from": "AuditLog", "to": "User", "owner_alias": "user", "inverse_alias": "auditLogs"}}
]
EOF

Skipper.exe -cli-apply-patch project.skipper -patch changes.json -output project.skipper -quiet

Step 3 — Create a migration for the modifications:

Skipper.exe -cli-create-migration project.skipper -quiet

Step 4 — Export the generated code:

Skipper.exe -cli-export project.skipper -quiet

The -skip-initial-migrations flag in the import step tells Skipper not to generate a migration for the initial database state, since those tables already exist. Migrations will only be created for changes made after the import.

Comparing Versions

Use the -cli-compare verb to see exactly what changed between two versions of a Skipper project file. This is useful for reviewing changes before creating a migration, or for auditing what changed between releases.

Skipper.exe -cli-compare project.skipper project-previous.skipper -quiet

The output includes a summary of added, removed, modified, and identical objects, plus a detailed list of each change:

{
  "status": "ok",
  "data": {
    "summary": {
      "added": 2,
      "removed": 0,
      "modified": 3,
      "identical": 15
    },
    "items": [
      {"action": "added", "type": "entity", "name": "AuditLog"},
      {"action": "added", "type": "field", "name": "AuditLog.action"},
      {"action": "modified", "type": "field", "name": "User.email", "details": "size: 100 -> 255"},
      {"action": "modified", "type": "entity", "name": "Product", "details": "namespace changed"},
      {"action": "modified", "type": "association", "name": "Order->Customer", "details": "alias changed"}
    ],
    "input_new": "project.skipper",
    "input_old": "project-previous.skipper"
  }
}

You can combine this with version control. For example, compare the current project file against the last committed version to preview pending migration content:

# Extract the previous version from git
git show HEAD:project.skipper > /tmp/project-old.skipper

# Compare current vs. committed
Skipper.exe -cli-compare project.skipper /tmp/project-old.skipper -quiet | jq '.data.summary'

Automating in CI/CD

You can automate migration creation as part of your CI/CD pipeline. The following script detects schema changes, creates a migration if needed, exports the code, and commits the result.

#!/bin/bash
# CI script: auto-create migrations on schema changes
set -e

PROJECT="project.skipper"
export QT_QPA_PLATFORM=offscreen

echo "Validating schema..."
RESULT=$(Skipper.exe -cli-validate "$PROJECT" -quiet)
ERRORS=$(echo "$RESULT" | jq '.data.summary.error_count')
if [ "$ERRORS" -gt 0 ]; then
    echo "Schema validation failed with $ERRORS error(s):"
    echo "$RESULT" | jq -r '.data.issues[] | "  \(.severity): \(.message)"'
    exit 1
fi

echo "Checking for pending changes..."
RESULT=$(Skipper.exe -cli-create-migration "$PROJECT" -quiet)
CREATED=$(echo "$RESULT" | jq -r '.data.created')

if [ "$CREATED" = "true" ]; then
    echo "New migration created. Exporting code..."
    RESULT=$(Skipper.exe -cli-export "$PROJECT" -quiet)
    FILES=$(echo "$RESULT" | jq '.data.files_written | length')
    echo "Exported $FILES file(s)."

    # List newly generated files
    echo "Generated files:"
    echo "$RESULT" | jq -r '.data.files_written[] | "  \(.path) (\(.bytes) bytes)"'

    # Optionally commit the results
    git add -A
    git commit -m "Auto-generate migration from schema changes"
else
    REASON=$(echo "$RESULT" | jq -r '.data.reason // "unknown"')
    echo "No migration created: $REASON"
fi

echo "Done."

This script can run as a scheduled CI job, a post-merge hook, or as part of a pull request workflow. It ensures that migration files are always in sync with the schema and that no manual step is forgotten.