var F=Object.defineProperty;var G=(A)=>A;function H(A,B){this[A]=G.bind(null,B)}var J=(A,B)=>{for(var D in B)F(A,D,{get:B[D],enumerable:!0,configurable:!0,set:H.bind(B,D)})};var K=(A,B)=>()=>(A&&(B=A(A=0)),B);import E from"@contractspec/lib.ui-link";import{ChevronRight as I}from"lucide-react";import{jsx as q,jsxs as z}from"react/jsx-runtime";function Q(){return z("div",{className:"space-y-8",children:[z("div",{className:"space-y-4",children:[q("h1",{className:"font-bold text-4xl",children:"Migrations"}),z("p",{className:"text-muted-foreground",children:["A ",q("strong",{children:"schema migration"})," (also called a database migration) is a set of incremental, reversible changes to a database schema. According to"," ",q("a",{href:"https://en.wikipedia.org/wiki/Schema_migration",target:"_blank",rel:"noopener noreferrer",className:"text-violet-400 hover:text-violet-300",children:"Wikipedia"}),`, schema migrations "allow the database schema to evolve as the application's requirements change, while preserving existing data."`]})]}),z("div",{className:"space-y-4",children:[q("h2",{className:"font-bold text-2xl",children:"Why migrations matter"}),q("p",{className:"text-muted-foreground",children:"As your application evolves, you'll need to change your data model—adding new fields, renaming tables, changing data types, or restructuring relationships. Without a disciplined approach, these changes can lead to:"}),z("ul",{className:"list-inside list-disc space-y-2 text-muted-foreground",children:[q("li",{children:"Data loss or corruption"}),q("li",{children:"Downtime during deployments"}),q("li",{children:"Inconsistencies between environments (dev, staging, production)"}),q("li",{children:"Difficulty rolling back failed changes"})]}),q("p",{className:"text-muted-foreground",children:"Migrations solve these problems by treating schema changes as versioned, tested, and reversible operations."})]}),z("div",{className:"space-y-4",children:[q("h2",{className:"font-bold text-2xl",children:"How MigrationSpec works"}),z("p",{className:"text-muted-foreground",children:["In ContractSpec, migrations are defined using"," ",q("strong",{children:"MigrationSpec"}),". Each migration has:"]}),z("ul",{className:"list-inside list-disc space-y-2 text-muted-foreground",children:[z("li",{children:[q("strong",{children:"Version"}),' – A unique identifier (e.g., "2025-11-13-001") that determines the order of execution.']}),z("li",{children:[q("strong",{children:"Up function"}),` – The forward migration that applies the change (e.g., "add column 'email_verified'").`]}),z("li",{children:[q("strong",{children:"Down function"}),` – The reverse migration that undoes the change (e.g., "drop column 'email_verified'").`]}),z("li",{children:[q("strong",{children:"Dependencies"})," – Other migrations that must run before this one."]}),z("li",{children:[q("strong",{children:"Validation"}),' – Optional checks to ensure the migration succeeded (e.g., "verify all users have an email address").']})]})]}),z("div",{className:"space-y-4",children:[q("h2",{className:"font-bold text-2xl",children:"Example MigrationSpec"}),q("p",{className:"text-muted-foreground",children:"Here's a migration that adds an email verification field to the users table:"}),q("div",{className:"overflow-x-auto rounded-lg border border-border bg-background/50 p-4 font-mono text-muted-foreground text-sm",children:q("pre",{children:`migrationId: add-email-verified
version: 2025-11-13-001
dependencies: []

up:
  - sql: |
      ALTER TABLE users
      ADD COLUMN email_verified BOOLEAN DEFAULT FALSE NOT NULL;
  - sql: |
      CREATE INDEX idx_users_email_verified
      ON users(email_verified);

down:
  - sql: |
      DROP INDEX idx_users_email_verified;
  - sql: |
      ALTER TABLE users
      DROP COLUMN email_verified;

validation:
  - sql: |
      SELECT COUNT(*) FROM users
      WHERE email_verified IS NULL;
    expectZeroRows: true`})})]}),z("div",{className:"space-y-4",children:[q("h2",{className:"font-bold text-2xl",children:"Running migrations"}),q("p",{className:"text-muted-foreground",children:"Migrations are applied automatically during deployment. The ContractSpec runtime:"}),z("ol",{className:"list-inside list-decimal space-y-2 text-muted-foreground",children:[q("li",{children:"Checks which migrations have already been applied (stored in a migrations table)."}),q("li",{children:"Identifies new migrations that need to run."}),q("li",{children:"Executes them in order, respecting dependencies."}),q("li",{children:"Runs validation checks to ensure success."}),q("li",{children:"Records the migration as applied."})]}),q("p",{className:"text-muted-foreground",children:"If a migration fails, the deployment is aborted, and the system remains in its previous state. You can then fix the migration and redeploy."})]}),z("div",{className:"space-y-4",children:[q("h2",{className:"font-bold text-2xl",children:"Rolling back migrations"}),z("p",{className:"text-muted-foreground",children:["If you need to roll back a deployment, ContractSpec automatically runs the ",q("strong",{children:"down"})," functions of any migrations that were applied. This restores the database to its previous state."]}),q("p",{className:"text-muted-foreground",children:"Note that rollbacks are not always possible—for example, if you've deleted a column, you cannot recover the data unless you have a backup. For destructive changes, it's best to use a multi-step migration:"}),z("ol",{className:"list-inside list-decimal space-y-2 text-muted-foreground",children:[q("li",{children:"Add the new column (reversible)."}),q("li",{children:"Backfill data from the old column to the new column (reversible)."}),q("li",{children:"Update application code to use the new column (reversible)."}),q("li",{children:"Drop the old column (irreversible—only do this after confirming the new column works)."})]})]}),z("div",{className:"space-y-4",children:[q("h2",{className:"font-bold text-2xl",children:"Best practices"}),z("ul",{className:"list-inside list-disc space-y-2 text-muted-foreground",children:[z("li",{children:[q("strong",{children:"Test migrations locally"})," – Run them against a copy of production data to catch issues before deploying."]}),z("li",{children:[q("strong",{children:"Keep migrations small"})," – Each migration should do one thing. This makes them easier to understand and roll back."]}),z("li",{children:[q("strong",{children:"Write reversible migrations"})," – Always provide a down function, even if you don't plan to roll back."]}),z("li",{children:[q("strong",{children:"Use transactions"})," – Wrap migrations in database transactions so they either fully succeed or fully fail."]}),z("li",{children:[q("strong",{children:"Avoid destructive changes"})," – Prefer additive changes (adding columns) over destructive ones (dropping columns). If you must delete data, archive it first."]}),z("li",{children:[q("strong",{children:"Version your migrations"})," – Use timestamps or sequential numbers to ensure migrations run in the correct order."]}),z("li",{children:[q("strong",{children:"Document breaking changes"})," – If a migration requires application code changes, note this in the migration description."]})]})]}),z("div",{className:"space-y-4",children:[q("h2",{className:"font-bold text-2xl",children:"Zero-downtime migrations"}),q("p",{className:"text-muted-foreground",children:"Some migrations can cause downtime if not handled carefully. For example, adding a NOT NULL column to a large table can lock the table for minutes. To avoid this, use a multi-step approach:"}),z("ol",{className:"list-inside list-decimal space-y-2 text-muted-foreground",children:[q("li",{children:"Add the column as nullable."}),q("li",{children:"Backfill the column in batches (without locking the table)."}),q("li",{children:"Add the NOT NULL constraint once all rows are populated."})]}),q("p",{className:"text-muted-foreground",children:"ContractSpec's migration system supports this pattern by allowing you to split a logical change into multiple versioned migrations."})]}),z("div",{className:"flex items-center gap-4 pt-4",children:[q(E,{href:"/docs/safety/auditing",className:"btn-ghost",children:"Previous: Audit Logs"}),z(E,{href:"/docs/advanced/renderers",className:"btn-primary",children:["Next: Advanced Topics ",q(I,{size:16})]})]})]})}export{Q as SafetyMigrationsPage};
