Every developer has their own workflow for promoting database changes from development to production, but this becomes an especially tricky problem in certain applications – for example, codegen platforms. In platforms like Replit, each user may be building multiple versions of their app / running experiments in parallel while production environments can continue receiving writes while a new version is being built.
Applications that look like this (or essentially any system that maintains many Postgres environments at once, each reflecting different states) face similar challenges:
- How do you test changes safely in isolation?
- How do you promote schema and data to production without losing writes?
- How do you refresh development with the latest production data?
- How do you roll back instantly if something goes wrong?
- And how do you do all of this without maintaining multiple disconnected databases or complex migration pipelines?
Customers have asked us these questions many times at Neon: we support codegen platforms like Replit, CMS systems like Strapi, and many other applications that need a dev <> prod workflow that’s programmable, efficient, and fast to execute across hundreds or thousands of environments. This blog post walks through a solution we’ve presented to these customers and ultimately implemented in production, so you can build your own setup without even talking to us.
Fun fact: I was a Solution Architect at Neon before moving to DevRel, so I can confidently say this workflow is true and tested.
The Use Case: Multiple Environments, Diverging Data and Schema
Let’s first take a look at the real workflows that pushed us to formalize this pattern. These examples come directly from customer conversations and they’re representative of a broad class of applications.
Promoting from preview to production, with prod writes in between
This fits a platform where customers edit content in preview environments before publishing. In the meantime, production isn’t static. It keeps receiving writes while a preview is open, such as form submissions or content edits from live users.
The desired workflow looks like this:
- Create a preview environment to stage CMS or application changes
- Modify data and schema safely in that preview
- Publish those changes to production once they’re validated
- Ensure no production writes are lost in the process
- Avoid long waits (milliseconds to one second is fine, minutes are not)
This is a classic scenario where traditional “migration-only” workflows break down. Production and preview can diverge, and manually merging database states would be very error-prone and operationally risky. This workflow is applied at scale, so there’s also additional concerns to think about:
- Costs (how to maintain multiple long-lived environments efficiently)
- Stale previews (what happens when previews pile up or go unused)
- Endpoint behavior (is it necessary to switch endpoints or copy data on publish)
- Data safety (how to prevent or recover from data loss when promoting)
Promoting from preview to production, with read-only prod
This scenario look similar vs the above, but with one key difference – production is read-only. All edits happen in previews, and only one preview will be chosen for publishing. The requirements:
- Ability to spin up many previews quickly
- Promote one preview to production cleanly
Keep costs predictable with a potentially large number of previews - Delete stale environments at any time without cleanup issues
- Publish changes without switching endpoints or rewriting application code
The workflow described in this blog post serves both of these scenarios.
The Tool for the Job: Neon Snapshots
So, to recap the fundamental problem: when you have multiple environments that evolve independently, there is no safe way to “merge” two diverged database states. Code merges cleanly because files are text, databases do not. To circumvent this problem, our workflow is going to rely on Neon snapshots, a feature built directly into Neon’s storage architecture.
What Neon snapshots are
A Neon snapshot captures both data and schema from a branch at a precise point in time. It is a logical, point-in-time snapshot that represents the full state of a branch in a way that can be restored instantly. Neon snapshots are a logical construct inside Neon’s decoupled storage engine, backed by the same architecture that powers branching and point-in-time restore – this gives them unique properties:
- They capture logical database state (data + schema)
- Can be restored to any branch in the same project
- Restores are instant, without copying physical files
What they are not
This is important, since “snapshot” means different things across different Postgres providers and cloud databases. Neon snapshots are not
- filesystem-level snapshots of a VM
- EBS or disk snapshots
- incremental WAL backups
The Snapshot-Based Promotion Workflow: How It Works End to End
With Neon snapshots defined, we can now walk through the workflow that many Neon customers run in production today. The basis is simple: to create two isolated root branches, prod and dev, and use snapshots to safely move changes between them.
Phase 1: Creating isolated roots for prod and dev
The first step is to give production and development their own independent root branches. This ensures that dev environments are fully isolated while still starting from a consistent production baseline.
The setup looks like this:
- Start with your existing
prodbranch. This is your live production environment. - Take a snapshot of
prod. This captures the exact data + schema state of production. - Restore the snapshot and name the restored branch
dev. When restoring a snapshot in Neon, you can specify the name of the new branch directly using the restore API.
You now have two independent root branches:
prod(your live environment)dev(your isolated development environment)
From here, prod and dev share the same initial state, but they’re no longer linked – changes in one won’t affect the other.
Phase 2: Building different versions
- Use the
devbranch as your working environment. All application updates / schema changes begin on thedevbranch. Because it’s a root branch, it behaves like a standalone database but still preserves a clean lineage back to the original production state. - Create short-lived child branches for previews or PR workflows. Create temporary branches for each feature, experiment, or user-level preview environment (
dev_feature_x,dev_feature_y,dev_preview_123). - Point your versioning system / previews / dev environments to the short-lived branches.
- When a change is validated, apply changes back to dev. E.g. the end-user is ready to promote a new version, or a preview passes all checks. Neon does not directly merge branches as you’re used to in Git ( this is intentional: merging diverged database states is not safe or well-defined in Postgres) so for this step, teams use their preferred method to apply changes back to
dev, e.g. migration files or scripts.
At the end of this phase, the dev branch represents the next production candidate.
Phase 3: Promote changes to production
Promotion is where snapshots shine – instead of merging diverged states, you replace production with a known-good copy of dev (the one you got at the end of the last phase).
- Snapshot
prod(for potential rollback). Before promoting anything, take a snapshot of the currentprodbranch. This snapshot becomes your recovery point if you ever need to roll back. - Snapshot dev (for promotion). Next, capture the state of the
devbranch that you want to publish.This snapshot represents the exact version you’ll be deploying to production. - Restore the
devsnapshot onto prod. Restoring a snapshot instantly rewritesprodto matchdev, while keeping production endpoints the same. The only visible effect is that active production connections are dropped during the restore (typically milliseconds). This is the core of the workflow: promotion = restore a snapshot of dev onto prod. prodis now the new published version. With promotion complete, development continues ondevtoward the next version, and production stays stable until it’s time to publish again.
A backup branch (old prod) will be created automatically after you restore. You can keep it briefly for sanity checks, delete it immediately, or assign a TTL for automatic cleanup.
Production writes after the snapshot will be lost
For many use cases, this is perfectly acceptable because production data is either read-only or not user-generated (and can be safely discarded). But this may not be safe for every application. If production writes must be preserved, ensure your system either treats production as read-only, moves all writes to preview/dev branches, or performs application-level backfilling or reconciliation after promotion.
Phase 4: Refreshing dev with the latest production data
After you’ve promoted a new version to production, the dev branch will eventually become outdated. Refreshing dev ensures that the next version is built on an up-to-date production baseline:
- Snapshot
prod. Create a snapshot of the current production environment to capture the latest data + schema in its live state. - Restore the snapshot onto
dev.Restoring instantly rewrites thedevbranch to match production while keeping the same branch ID and endpoint string.
Note: A backup branch (old dev) will be created automatically after you restore. You can keep it briefly for sanity checks, delete it immediately, or assign a TTL for automatic cleanup.
A potential phase 5: Rolling production back if needed
Even in the safest workflows, accidents happen. If you ever have to roll back production, here’s the safest way to do it:
- Identify the snapshot you want to roll back to. For example, the pre-promotion snapshot from earlier.
- Restore the snapshot onto prod. This works just like during Phase 3 (promotion). estore.
You can delete it immediately or keep it for short-term verification.
Similarly as earlier, a backup branch (old prod) will be created automatically after you restore. You can keep it briefly for sanity checks, delete it immediately, or assign a TTL for automatic cleanup.
Operational Considerations
Running this workflow at scale requires a good understanding of how Neon snapshots behave, how branches are billed, and how to structure your cleanup and retention strategies. The good news is that snapshots and branches are lightweight by design, and the workflow adapts well to large multi-environment systems.
Naming conventions
Clear naming will make automation much easier. Teams use things like prod_snap_2025-01-17_pre-promotion, dev_snap_2025-01-17_candidate_v2, prod_snap_2025-01-17_after-promotion.
Cost model
- Root branches (like
prodanddev) are billed based on their logical size, the size of the data they represent. - Snapshots are also billed based on logical size. (PS: If you’re reading this during the beta period for snapshots, they’ll incur no costs.)
- Child branches are extremely affordable, since they share underlying data until changes are written.
A good approach to reduce costs is to keep only the snapshots you need for recovery and promotion, and to set up branch expiration dates so branches get cleaned up automatically. You can keep two families of snapshots:
- Production snapshots, retained longer for potential rollback
- Development snapshots, retained a briefly as possible (hours max) for promotion cycles
Restore behavior (connection drops)
Every restore operation briefly drops active connections to the target branch. These interruptions are typically measured in milliseconds, occasionally up to a second. Most agent platforms and CMS-style user flows find this latency acceptable, but it’s important to design application code to retry queries automatically.
Build This Workflow Into Your Platform
This snapshot-based promotion workflow gives you a safe, repeatable, and scalable way to version both data and schema, something traditional migration workflows can’t reliably offer. This workflow is already running in production across agent platforms, CMS builders, and other systems that manage many environments at once.
If you want to adopt the same model, you can try it today on Neon – give it a spin and see how simple safe database versioning can be!


