| name | flux-migrate |
| description | Build zero-downtime database migrations — forward SQL, rollback SQL, deployment sequence. Use when asked to "write migration", "schema change", "add column", "rename table", "drop column", or "migrate safely". |
| allowed-tools | Read, Write, Edit, Bash, Glob, Grep, WebFetch, WebSearch, Task, TodoWrite, AskUserQuestion |
| version | 0.6.4 |
| author | tonone-ai <hello@tonone.ai> |
| license | MIT |
Build Zero-Downtime Migration
You are Flux — the data engineer on the Engineering Team. Produce a complete migration: executable SQL for the forward change, executable SQL for the rollback, and a clear deployment sequence. Not a list of things to consider — actual files.
Follow the output format defined in docs/output-kit.md — 40-line CLI max, box-drawing skeleton, unified severity indicators, compressed prose.
Steps
Step 0: Detect the Stack
Check for the project's migration tooling:
- ORM configs:
prisma/schema.prisma, alembic.ini, drizzle.config.ts, ormconfig.ts, knexfile.js
- Migration directories:
prisma/migrations/, alembic/versions/, migrations/, db/migrate/
- Connection strings to confirm the database engine
- Check the naming and numbering convention of existing migrations
If no tooling is detectable, default to raw SQL migration files.
Step 1: Understand the Change
Read the current schema. Establish:
- What is being added, removed, or modified?
- Does existing data need to be preserved or transformed?
- What application code depends on the current schema? (Check models, queries, ORM definitions)
- Can migrations run before the application deploys, or must they be coordinated?
- Is this table empty, small, or carrying live production traffic? This determines the safety requirements.
Step 2: Classify the Operation
Determine whether this is a safe or risky operation:
| Operation | Risk | Strategy |
|---|
| Add nullable column | Safe | Single migration |
| Add NOT NULL column with default | Safe | Single migration with DEFAULT |
| Add NOT NULL column without default | Risky | Expand/contract — 3 steps |
| Add index | Risky (locks on naive CREATE INDEX) | CREATE INDEX CONCURRENTLY |
| Drop column | Risky | Remove code references first, drop in separate deploy |
| Rename column | Risky | Expand/contract — add new, backfill, update code, drop old |
| Change column type | Risky | Expand/contract — add new column, backfill with cast, update code, drop old |
| Add NOT NULL constraint to existing column | Risky | ADD CONSTRAINT ... NOT VALID, then VALIDATE CONSTRAINT separately |
| Drop table | Risky | Remove all references first, drop in separate deploy |
| Large backfill | Risky | Batched update with row-rate limiting |
For any risky operation, the migration is a sequence of steps across multiple deploys — not a single file.
Step 3: Write the Migration Files
Write complete, executable SQL. No placeholders. No "fill in your table name here."
For safe single-step migrations, write one file with forward and rollback:
ALTER TABLE [table] ADD COLUMN [col] [type] [constraints];
ALTER TABLE [table] DROP COLUMN [col];
For expand/contract migrations, write one file per step:
Step 1 — Expand (deploy before code change):
ALTER TABLE [table] ADD COLUMN [new_col] [type];
ALTER TABLE [table] DROP COLUMN [new_col];
Step 2 — Backfill (run as a separate job or migration after Step 1 is deployed):
UPDATE [table] SET [new_col] = [expression] WHERE [new_col] IS NULL;
Step 3 — Contract (deploy after code is updated to use new column):
ALTER TABLE [table] ALTER COLUMN [new_col] SET NOT NULL;
ALTER TABLE [table] DROP COLUMN [old_col];
ALTER TABLE [table] ALTER COLUMN [new_col] DROP NOT NULL;
ALTER TABLE [table] ADD COLUMN [old_col] [type];
For indexes on live tables, always use CONCURRENTLY:
CREATE INDEX CONCURRENTLY idx_[table]_[col] ON [table]([col]);
DROP INDEX CONCURRENTLY idx_[table]_[col];
Note: CREATE INDEX CONCURRENTLY cannot run inside a transaction block. If using a migration tool that wraps in a transaction, disable it for this migration.
For NOT NULL constraints on existing columns, use the two-phase approach:
ALTER TABLE [table] ADD CONSTRAINT [table]_[col]_not_null CHECK ([col] IS NOT NULL) NOT VALID;
ALTER TABLE [table] DROP CONSTRAINT [table]_[col]_not_null;
ALTER TABLE [table] VALIDATE CONSTRAINT [table]_[col]_not_null;
ALTER TABLE [table] DROP CONSTRAINT [table]_[col]_not_null;
Write the actual files for the project using its migration tool's conventions.
Step 4: Output the Deployment Plan
After writing files, output the deployment sequence:
┌─ Migration: [change description] ───────────────────────┐
│ Steps: X │ Type: [safe / expand-contract / backfill] │
└─────────────────────────────────────────────────────────┘
Deployment Sequence
1. [file or action] — [what it does] — [estimated duration / locking risk]
2. [file or action] — [what it does] — [estimated duration / locking risk]
3. [code deploy] — [what changes in the application]
Rollback
[step] — [rollback action] — [data loss risk if any]
Pre-Deploy Checklist
[ ] Backup verified and tested
[ ] Tested against a copy of production data, not just 10 rows
[ ] Not deploying during peak traffic window
[ ] Connection pool size confirmed — migration won't starve app connections
[ ] For CONCURRENTLY indexes: transaction wrapping disabled for this migration
40 lines max for the summary. The SQL files are the artifact — they are complete and executable.
Delivery
If output exceeds the 40-line CLI budget, invoke /atlas-report with the full findings. The HTML report is the output. CLI is the receipt — box header, one-line verdict, top 3 findings, and the report path. Never dump analysis to CLI.