Cutovers
Operator-assisted promotion of a preview database to production, with a verified pre-cutover backup taken first.
What a cutover is
A cutover takes a preview database you have already built and verified — a rehearsed schema migration, a cleaned-up import, a restructured dataset — and makes its contents the project's production data. It is the "this preview is the new production" operation.
It is deliberately not self-service. You open a cutover request; a platform operator reviews it, schedules it with you, and executes it. Overwriting production from a human-prepared database is the kind of action that benefits from a second pair of eyes, and we would rather be slow here than sorry.
Cutover vs. restore
Both end with production overwritten, so pick by where the desired state lives:
| You want production to become... | Use |
|---|---|
| A past state of production (backup, restore point, or timestamp) | Restore with target_kind: "project" — self-service, gated by a confirmation flag and the org admin role |
| The current state of a preview database you prepared | Cutover — operator-assisted |
If you only want to inspect a candidate state, neither: restore into a preview and look around first.
The flow
- Request. From the project's Previews tab (the Promote action on a ready preview) or
POST /v1/projects/{id}/cutover-requestswith thepreview_id. You can attach acustomer_note(up to 1000 characters) and anexternal_ticket_ref(up to 120 characters) — a reference to the support thread or ticket where the cutover is coordinated. A ticket reference is required before the cutover can be executed, so include it up front or expect the operator to ask for it. - Review. The request opens in
openstate. An operator acknowledges it (acked) or rejects it with a stated reason (rejected). One open request per preview at a time. - Execution. The operator triggers the promotion. Before anything is overwritten, a backup of the current production database is taken and verified, labeled
pre-cutover-<request-id>— it appears in your backups list like any other and is your rollback path. The preview's contents are then copied over the production database. The request moves throughin_progresstocompleted.
The preview must be ready and not expired for the whole flow — watch the TTL, and extend it if review takes longer than the preview lives.
What changes and what does not
- Connection strings do not change. The project keeps its host, ports, database name, role, and password. Apps reconnect to the same URLs and see the new data.
- The source preview database is not consumed — its contents are copied, and the preview remains until its TTL removes it.
- The project passes through a
restoringstate while the job runs; it does not accept other lifecycle operations during that window.
After completion
restore.completedandjob.completedwebhook events fire.- Connected Vercel and Netlify integrations re-push env vars (unchanged here, but the sync runs for consistency).
- The audit trail records the full lifecycle:
cutover.requested,cutover.acked(orcutover.rejected),cutover.promote_started, and aproduction_overwrite_restoreevent carrying the pre-cutover backup ID.
Rolling back
The pre-cutover backup is a normal backup. If the cutover turns out to be a mistake, restore from it — into a preview first to confirm, then over production.
Limitations, stated plainly
- Cutovers run when an operator runs them. There is no SLA on turnaround; the
external_ticket_refexists precisely so timing is agreed between humans. - The promotion job does not retry on failure — a failed cutover stays failed and an operator investigates rather than the system blindly re-overwriting production.
- There is no CLI command for cutovers today; use the dashboard or the API.