Detect v1 artifacts, run schema migrations, roll back cleanly, and generate SQL with AI assistance.
# Check whether any v1 artifacts need migration
nself migrate detect
# Run all pending database migrations
nself migrate run
# Roll back the last migration
nself migrate rollback
# Generate a new migration from a plain-English description
nself migrate generate "add stripe_customer_id to users table"nself migrate <SUBCOMMAND> [FLAGS]nself migrate handles two related but distinct concerns: upgrading project artifacts from ɳSelf v1 to v2 format, and managing the Postgres schema migration lifecycle via Drizzle.
When upgrading from v1, run detect first to get a summary of what will change, thenrun to apply it. For day-to-day schema work, use generate to create a timestamped SQL file (with optional AI drafting) and run to apply pending migrations.
Migrations are stored in backend/migrations/ and tracked in the _nself_migrations table. Drizzle is used for migration only — never for direct ORM queries against np_* tables. All runtime queries go through Hasura GraphQL.
Scan the project directory for v1 artifacts (old docker-compose formats, legacy env keys, deprecated plugin manifests, old nginx config shapes) and print a summary of what run will change. Nothing is modified.
| Flag | Type | Default | Description |
|---|---|---|---|
--json | bool | false | Output findings as JSON for automation |
--strict | bool | false | Exit 1 if any v1 artifacts are found (useful in CI) |
nself migrate detect
# ARTIFACT STATUS NOTES
# docker-compose.yml migrate v1 format — will regenerate via nself build
# .env migrate 4 deprecated keys found: HASURA_VERSION, ...
# nginx/sites/api.conf migrate v1 upstream naming — will regenerate
# plugins/ai/manifest.json ok already v2 formatApply all pending migrations. In v1-to-v2 mode (when detect found artifacts), this also upgrades the project files. For schema-only mode (no v1 artifacts), it applies pending SQL files frombackend/migrations/.
| Flag | Type | Default | Description |
|---|---|---|---|
--dry-run | bool | false | Show what would be applied without executing |
--env | string | current | Target environment: dev, staging, prod |
--to | string | Apply only up to this migration timestamp (e.g. 20260507120000) | |
--skip-backup | bool | false | Skip the automatic pre-migration backup (dev only; blocked in prod) |
nself migrate run
nself migrate run --dry-run
nself migrate run --env staging
nself migrate run --to 20260507120000Undo the most recently applied migration by executing its down.sql file. Creates a snapshot before rolling back.
| Flag | Type | Default | Description |
|---|---|---|---|
--steps | int | 1 | Number of migrations to roll back |
--to | string | Roll back to a specific migration timestamp | |
--env | string | current | Target environment |
nself migrate rollback
nself migrate rollback --steps 3
nself migrate rollback --to 20260506000000Create a new timestamped migration file in backend/migrations/. When the ai plugin is installed, the description is sent to your configured LLM which drafts the SQL for you to review and edit before committing.
| Flag | Type | Default | Description |
|---|---|---|---|
--no-ai | bool | false | Create an empty migration file without AI assistance |
--model | string | project default | Override the LLM used for SQL generation |
# AI-assisted (requires ai plugin)
nself migrate generate "add stripe_customer_id to users table"
# → Created: backend/migrations/20260507142301_add_stripe_customer_id_to_users.sql
# → AI draft written — review before running nself migrate run
# Empty file for manual editing
nself migrate generate "custom rls policy" --no-aicd my-project
nself migrate detect # see what will change
nself migrate run --dry-run # confirm the plan
nself maintenance enable # put the site in maintenance mode
nself migrate run # apply the upgrade
nself maintenance disable # bring the site back upnself migrate generate "add last_login_at column to users"
# Edit the generated file if needed
nself migrate run --dry-run
nself migrate run# In your CI pipeline:
nself migrate detect --strict # fails if v1 artifacts remain
nself migrate run --dry-run # confirms pending migrations exist (or not)backend/migrations/
20260501000000_initial_schema.sql
20260501000000_initial_schema.down.sql ← rollback SQL
20260507142301_add_stripe_customer_id.sql
20260507142301_add_stripe_customer_id.down.sqlDATABASE_URL — Postgres connection string (loaded automatically from active env)NSELF_AI_MODEL — default model for generate AI assistance0 — success (or detect found no issues)1 — migration failed; database left unchanged2 — invalid arguments3 — v1 artifacts detected (only when --strict is set)