Post image

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:

  1. Create a preview environment to stage CMS or application changes
  2. Modify data and schema safely in that preview
  3. Publish those changes to production once they’re validated
  4. Ensure no production writes are lost in the process
  5. 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:

  1. Ability to spin up many previews quickly
  2. Promote one preview to production cleanly
    Keep costs predictable with a potentially large number of previews
  3. Delete stale environments at any time without cleanup issues
  4. 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: 

  1. Start with your existing prod branch. This is your live production environment.
  2. Take a snapshot of prod. This captures the exact data + schema state of production.
  3. 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.
Post image

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 

  1. Use the dev branch as your working environment. All application updates / schema changes begin on the dev branch. Because it’s a root branch, it behaves like a standalone database but still preserves a clean lineage back to the original production state.
  2. 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). 
  3. Point your versioning system / previews / dev environments to the short-lived branches.
  4. 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.
Post image

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). 

  1. Snapshot prod (for potential rollback). Before promoting anything, take a snapshot of the current prod branch. This snapshot becomes your recovery point if you ever need to roll back.
  2. Snapshot dev (for promotion). Next, capture the state of the dev branch that you want to publish.This snapshot represents the exact version you’ll be deploying to production.
  3. Restore the dev snapshot onto prod. Restoring a snapshot instantly rewrites prod to match dev, 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.
  4. prod is now the new published version. With promotion complete, development continues on dev toward 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.

Post image

Production writes after the snapshot will be lost

It's important to note that restoring the dev snapshot onto prod completely replaces the production branch with the state of dev at the time the snapshot was taken. This means any production data created or modified after the production snapshot (taken at the start of this phase) will not be present after the restore.

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: 

  1. Snapshot prod. Create a snapshot of the current production environment to capture the latest data + schema in its live state.
  2. Restore the snapshot onto dev.Restoring instantly rewrites the dev branch 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.

Post image

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: 

  1. Identify the snapshot you want to roll back to. For example, the pre-promotion snapshot from earlier. 
  2. 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.

Post image

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 prod and dev) 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!

Apply to the Agent Plan

If you’re building a codegen platform, check out our Agent Plan for special pricing, resource-limits, and support.