Paste two SQL CREATE TABLE statements or JSON schemas — see a visual diff and get a generated migration script.
Databases enforce schemas at write time. Changing a schema without a migration leaves existing rows invalid or the app's ORM out of sync — causing 500 errors in production. Migrations are the contract between code version and data version.
Safe: adding a nullable column, adding an index concurrently, adding a table. Unsafe: dropping a column, renaming a column (breaks old code), changing a type, adding NOT NULL without a default (locks table on large datasets).
Expand-contract pattern: (1) add new column, (2) deploy code that writes to both old and new, (3) backfill old rows, (4) deploy code that reads new column, (5) drop old column. Each step is independently deployable and rollback-safe.
Flyway and Liquibase (Java/SQL-first). Alembic (Python/SQLAlchemy). Prisma Migrate (Node.js). Active Record Migrations (Rails). All track applied migrations in a schema_migrations table.
Sequential integers (V1, V2...) work for solo teams; timestamps (20240512_143000) avoid merge conflicts on feature branches. Never edit an already-applied migration — always add a new one.
Write a down migration for every up. Dropping columns in up = no rollback possible without restoring from backup. This is why expand-contract matters: you can always revert before the drop step.
JSON Schema is additive: adding optional fields is backward-compatible. Adding required fields, removing fields, or tightening validation breaks existing producers/consumers. Use additionalProperties: false carefully — it's a foot-gun in API versioning.
CREATE INDEX takes a full table lock in most databases. Use CREATE INDEX CONCURRENTLY (PostgreSQL) or online DDL (MySQL 8+) for production tables. Monitor index build progress via pg_stat_progress_create_index.