Snapshots as Checkpoints is a demo that showcases how to build a “checkpoint” abstraction for agent/codegen workflows using Neon’s snapshot and restore APIs. Each agent prompt produces a new checkpoint. You can jump back and forth between checkpoints to instantly revert schema and data.
This demo uses one persistent meta Postgres database and a dynamic app database per user session:
- meta database: stores auth user references (via Neon Auth),
projects
, andcheckpoints
(managed by Drizzle) - app database: created per user as a Neon project at demo start; its URL is saved in the
projects
table and used for all contacts reads/writes
Key docs in this repo:
- BRANCHING_DOCS.md: creating, listing, and deleting branches with the Neon API
- SNAPSHOT_DOCS.md: creating and restoring snapshots (one-step and multi-step)
- OPERATIONS_DOCS.md: Neon control-plane operations and polling semantics
Minimal checkpoint implementation using snapshots:
-
v1 prompt: “Create a contact list app … name + email” → app + DB created → snapshot s1
-
v2 prompt: “Add role and company” → schema + app updated → snapshot s2
-
v3 prompt: “Add tags” → schema + app updated → snapshot s3
Reverting is restoring a snapshot:
- revert to v1 → restore s1
- revert to v3 → restore s3
- Home page → Start demo: creates (or recreates) a Neon project for the signed-in user, stores it in the meta DB, applies the v1 mutation to that app DB, snapshots, and creates the first checkpoint
- Checkpoint page
/[checkpointId]
:- Top: timeline of checkpoints with jump actions
- Tabs: app | meta db | contacts schema
- app: interactive contacts table (v1/v2/v3 components)
- meta db:
checkpoints
table from the meta database - contacts schema: columns reported by
information_schema.columns
(from the app database)
- Actions: revert (apply snapshot), create/jump to next
- Next prompt: shows what the next mutation will do
Checkpoint page fetches data in parallel with Promise.all:
- contacts for the current version (using the app DB URL from the current project)
- contacts table schema (from the app DB's
information_schema
) - meta
checkpoints
rows (from the meta DB)
lib/neon/apply-snapshot.ts
calls Neon’s restore endpoint withfinalize_restore: true
and atarget_branch_id
(production branch), then collects operation IDs from the responselib/neon/operations.ts
polls each operation using the operations API until it reaches a terminal status (finished
,skipped
, orcancelled
)
See OPERATIONS_DOCS.md for operation semantics, and SNAPSHOT_DOCS.md for the restore flow.
Create a .env
file in the project root with these variables:
# Meta database (Drizzle-managed: users, projects, checkpoints)
DATABASE_URL=postgres://user:pass@host/meta_db
# Neon API access for creating/deleting projects, snapshots, restores
# This should be an org-wide API key with permissions for your Neon org
NEON_API_KEY=your_org_api_key
Notes:
DATABASE_URL
points to the meta database only. The app database URL is created dynamically per user and stored in theprojects
table.- The app uses the
production
branch of each user's Neon project as the root branch for snapshots/restores.
npm install
npm run dev
Open http://localhost:3000 and click “Start demo”. The app will:
- create (or recreate) a Neon project for the signed-in user and store it in the meta DB
- run the v1 mutation against that app DB and create the initial snapshot
- navigate to the first checkpoint route
- app/[checkpointId]/page.tsx: main page, tabs, actions, and parallel fetching
- lib/contacts.ts: schema mutations, CRUD, and contacts/schema queries
- lib/checkpoints.ts: meta DB
checkpoints
table and list/create/update - lib/neon/branches.ts: resolves the
production
branch id for a given Neon project - lib/neon/create-snapshot.ts: creates a snapshot on the production branch for a given Neon project
- lib/neon/apply-snapshot.ts: restore + wait for operations to finish for a given Neon project
- lib/neon/operations.ts: polls operation ids until terminal status for a given Neon project
Deploy with your platform of choice (e.g., Vercel). Provide the same environment variables in your deployment environment.