Browse all documentation

Migrations

Create, review, verify, and safely apply database migrations.

Ridu derives PostgreSQL and MongoDB migrations from executable Go config, but it never treats a schema diff as permission to change a database. The CLI writes an immutable artifact for review, verifies complete history in an isolated shadow target, and applies it only through an explicit command.

The ordinary workflow

Change application config, then create and inspect one artifact:

terminal
npm run ridu -- migrate create --name add-post-summary
npm run ridu -- migrate plan
npm run ridu -- migrate verify

Commit the *.ridu.json file with the config and generated-contract changes. Deploy the exact binary and artifact history that passed verification. This preparation example is not the MongoDB production cutover order; follow the exact sequence under Deployment and recovery.

Command Database connection What it does What it never does
create No Resolves current config, compares it with the latest artifact manifest, detects renames, binds a compiled transform when selected, plans phases, and writes one immutable artifact. It does not inspect or change the database.
plan Yes Compares local history with the database and shows each artifact, phase, step, and committed checkpoint. Add --json for automation. It does not apply a step.
status Yes Reports applied and pending artifacts and checks the exact ledger and adapter-managed physical state. It does not repair drift or apply history.
verify Yes Creates a random temporary PostgreSQL schema or MongoDB database, replays complete admitted history, checks final assertions/readiness, then drops that exact target. It does not test production data volume, lock timing, or content-specific collisions. It cannot stop at a phase or step.
up Yes Validates history and the ledger, takes the adapter’s bounded migration lock/lease, and applies pending work with durable resumption where supported. It does not invent a rollback or bypass a safety finding.

Every command except create requires a non-empty artifact history whose newest manifest digest matches executable config. This prevents a database from being reported as current while config and migrations describe different applications. Supply PostgreSQL or MongoDB through DATABASE_URL or --database-url.

What is in an artifact

An artifact records the information needed to identify and re-run the transition:

  • the full before and after manifests and their SHA-256 digests;
  • the artifact, planner, and runner contract versions;
  • stable phase and step IDs, execution modes, physical-state lineage, and a final assertion;
  • confirmed collection and field rename intent; and
  • machine-readable safety findings with notice, warning, or destructive severity.

PostgreSQL artifacts can use atomic transaction phases, checkpointed batch phases, and narrowly typed non-transactional concurrent-index phases. New MongoDB planner contract 2.0.0 artifacts emit only their typed physical index, confirmed rename, compiled-transform, retirement, and assertion steps; it does not embed arbitrary driver commands. Authenticated planner-1.0.0 history remains a supported immutable prefix to v2 and is validated and replayed rather than rewritten. Arbitrary non-transactional SQL is not admitted. Formatting-only JSON changes do not alter the canonical artifact digest, but renaming, reordering, removing, editing, or inserting applied history is detected by the database ledger.

Never edit an applied artifact. If a deployment needs correction, restore the committed history and create a new forward migration.

Renames preserve identity

When a slug or field path changes, create proposes only unambiguous one-to-one candidates:

text
Detected field rename "posts".title -> "posts".headline.
Preserve its existing data as a rename? [Y/n]

Confirm interactively or use --accept-renames only after reviewing every proposed match. Ridu can then preserve physical tables, columns, indexes, constraints, nested stored values, versions, auth state, task references, polymorphic relationships, and declared plugin reference keys as the specific transition requires.

Ambiguous mappings are rejected rather than guessed. Collection slug swaps and chains must be split into separate artifacts with a temporary slug so a value cannot be rewritten twice. Application task input and arbitrary JSON remain opaque; the generic runner never searches them heuristically.

Destructive and maintenance admission

Safety flags have the following scope:

Admission Accepted by Meaning
--allow-destructive create Record a planner-confirmed destructive finding in the artifact after review. It does not connect to or change a database.
--allow-maintenance verify, up Admit a traffic-sensitive phase after every old application process, writer, and worker has been stopped. Keep them stopped through retries until status is complete.
--allow-insecure-database database-backed commands Permit plaintext or bypass certificate verification only for a local PostgreSQL or MongoDB environment. create is offline and rejects the flag.
--allow-unbounded up, verify Permit an applicable zero runner wait/timeout. Ordinary production defaults remain bounded; MongoDB lease expiry is always bounded.

Deleting ordinary resources can require both destructive approval at creation and maintenance approval at execution because the runner also purges sessions, credentials, versions, tasks, preferences, locks, and reference-index state. Removing an upload collection also requires moving or deleting its external objects yourself; the database artifact cannot do that work, so the planner fails closed even with --allow-destructive.

Common safety codes

Stable codes are intended for CI policy and runbook search, not for bypass scripts.

Code What it protects Safe response
RIDU_MIGRATION_PLAN_MISMATCH The artifact no longer exactly matches the plan regenerated from its embedded manifests and rename intent. Restore or recreate the reviewed artifact; do not trust or apply the changed file.
RIDU_REFERENCE_SHAPE_DECREASE_UNSAFE Stored current values or version snapshots could retain dormant references after a field/target/cardinality decrease. Keep the shape, remove the entire owning root with typed retirement, or design an application-owned data-cleanup contract first.
RIDU_REFERENCE_RENAME_MAPPING_AMBIGUOUS A source or destination field is mapped more than once. Split the change into unambiguous artifacts.
RIDU_COLLECTION_SLUG_REWRITE_OVERLAP_UNSAFE A collection rename chain or swap could rewrite a value twice. Use a unique temporary slug across separate reviewed artifacts.
RIDU_UPLOAD_COLLECTION_REMOVAL_UNSAFE A database migration cannot manage external objects. Transfer/delete through upload operations, reconcile, and verify matched backups; retain the collection until a typed retirement path exists.
RIDU_AUTH_DISABLE_STATE_UNSAFE and related *_DISABLE_STATE_UNSAFE codes Disabling auth, API keys, recovery, verification, versions, drafts, locks, or trash could leave dormant state that reactivates later. Keep the capability enabled or introduce the narrower cleanup contract the finding requires.
RIDU_RETIRE_DEPENDENT_VERSION_HISTORY Resource retirement must also delete dependent owner history to prevent references from returning on restore. Treat the version-history loss as destructive and include it in backup, review, and acceptance.

The error is useful information. --allow-destructive does not silence semantic safeguards.

Applying and resuming

Shared artifact-envelope format 1 remains the committed history contract. PostgreSQL writes phase and step progress separately: an interrupted transaction leaves neither its data nor step rows, a batch resumes after its last committed keyset checkpoint, and a concurrent index resumes from catalog state or removes an invalid interrupted build before retrying the reviewed definition.

New MongoDB planner contract 2.0.0 artifacts use that same immutable format-1 envelope. The runner authenticates and replays a committed planner-1.0.0 prefix before v2 artifacts, takes a fenced, expiring lease, records completed steps durably, recognizes already-completed physical work, and resumes the same artifact after an interrupted process. It never treats process exit or lease expiry alone as completion.

Production defaults bound PostgreSQL advisory-lock, statement, batch, concurrent-index, and idle transaction work, plus MongoDB lease waits and complete migration operations. PostgreSQL up can stop after a committed boundary with --stop-after-phase or --stop-after-step; qualify a repeated ID as <artifact-name>/<boundary-id>. MongoDB rejects explicit stop boundaries and instead resumes from durable progress after interruption. verify always replays to completion.

Use plan --json and status --json to feed deployment automation. Do not infer success merely from process exit after a requested stop boundary: status must show the complete target history before application readiness can pass.

Deployment and recovery

Only binaries with the same manifest digest and migration-history fingerprint may overlap. Rehearse on a restored recovery point before production. For a MongoDB release with any new artifact, including an additive or same-manifest data-only artifact, use this exact production sequence:

  1. Drain every old application replica and worker.
  2. Run DATABASE_URL="$MONGODB_OPERATIONAL_URL" ridu migrate verify so shadow-database authority is scoped to that command. Append --allow-maintenance whenever the complete committed history contains semantic work, because clean-shadow verification replays every artifact.
  3. After verification succeeds, capture the matched selected-database and upload recovery point with a separate least-privilege credential such as $MONGODB_BACKUP_URL.
  4. Run DATABASE_URL="$MONGODB_MIGRATION_URL" ridu migrate up with the selected database-scoped application or controlled operator identity. Append --allow-maintenance only when the pending or incomplete history suffix contains semantic work.
  5. Run DATABASE_URL="$MONGODB_MIGRATION_URL" ridu migrate status and require complete history and exact Ridu-managed indexes.
  6. Start only the target release binary carrying the expected manifest and migration-history fingerprints using $MONGODB_APP_URL, then wait for /readyz.

Semantic work includes persisted content renames, compiled transforms, reference-index rebuilds, and typed resource retirement. MongoDB verify requires maintenance admission whenever any of that work appears in the complete committed history; up requires it only when the pending or incomplete suffix contains that work. The flag is an assertion that old writers are stopped, not a lock that stops them for you.

See PostgreSQL or MongoDB for connection and adapter-specific recovery configuration, Production for the wider cutover checklist, Security for trust boundaries, and Troubleshooting for failure-first diagnosis.