Running PostgreSQL in production while keeping development workflows fast and isolated is a problem every engineering team eventually hits. Neon solves this by separating storage from compute, offering instant database branching, and scaling to zero when idle — all while staying fully PostgreSQL-compatible. If you have ever wished you could spin up a copy of your production database for a pull request in under a second without paying for a second full instance, Neon is worth a serious look. This guide covers the architecture, branching workflow, autoscaling behavior, and how to decide whether Neon fits your stack.
- Neon is a serverless PostgreSQL platform built on a custom storage engine that separates compute (PostgreSQL processes) from storage (distributed page server).
- Database branching uses copy-on-write (CoW) to create instant, full-fidelity clones of any database — ideal for feature branches and preview environments.
- Autoscaling adjusts compute units (CU) between a configured minimum and maximum; scale-to-zero is available but introduces cold start latency.
- Built-in connection pooling via PgBouncer handles connection limits at the platform layer.
- Pricing is usage-based: you pay for active compute time and stored GBs separately.
What is Neon?
Neon is an open-source, serverless PostgreSQL provider. It launched in 2022 and is designed from the ground up for cloud-native workflows — not a managed wrapper around a conventional PostgreSQL instance. The core value proposition is that storage and compute are decoupled at the architecture level, which enables features that are impossible (or very expensive) to implement on traditional managed databases: instant branching, autoscaling down to zero compute, and time-travel queries via the storage layer's write-ahead log (WAL) history.
Neon runs fully compatible PostgreSQL (currently PostgreSQL 14, 15, 16, and 17). Any tool, driver, or ORM that works with standard PostgreSQL works with Neon without modification. The project is open source under the Apache 2.0 license, and the storage engine code is available on GitHub.
Architecture: Pageserver and Safekeeper Separation
Understanding Neon's architecture explains why branching and autoscaling work the way they do.
In a conventional PostgreSQL setup, compute and storage are tightly coupled — the PostgreSQL process writes directly to local disk. Neon breaks this into three distinct layers:
- Compute layer — Standard PostgreSQL processes. Stateless. Can be started, stopped, or scaled without touching stored data.
- Safekeeper layer — A cluster of nodes that receive and durably store the WAL stream from the compute layer. Safekeepers act as a distributed commit log, providing high durability before pages are materialized.
- Pageserver layer — Materializes pages from the WAL history on demand. Serves page reads to the compute layer over the network. Stores the full history of all pages, enabling branching at any point in time.
When a PostgreSQL compute node needs a page, it requests it from the Pageserver rather than reading from local disk. When it writes, the WAL goes to the Safekeepers first. This means a compute node carries no local state — it can be terminated and restarted instantly, and a new compute node picks up exactly where the previous one left off by reconnecting to the same Pageserver.
Because reads go over the network to the Pageserver, Neon is not suitable for workloads with extreme read latency sensitivity (for example, sub-millisecond random read requirements). For most OLTP workloads the additional latency is imperceptible, but benchmark your specific access patterns before committing.
Database Branching: Copy-on-Write Instant Clones
Database branching is the feature that differentiates Neon most clearly from other managed PostgreSQL providers. A branch in Neon is a copy-on-write clone of the storage layer at a specific WAL point. Creating a branch does not copy any data — it records a pointer to the parent's page history and begins diverging from that point forward. This makes branch creation instantaneous regardless of database size.
A branch is a fully independent PostgreSQL database. It has its own connection string, its own compute endpoint, and its own lifecycle. You can write to a branch without affecting the parent. When a branch is deleted, only the diverged pages are removed.
Common branching workflows include:
- Branch from production for testing — Create a branch from the production database endpoint, run destructive tests or schema migrations, then delete the branch. The production database is untouched.
- Preview environments per pull request — Each PR gets a database branch seeded from the latest production state. The branch is deleted when the PR closes.
- Point-in-time branching — Branch from a specific timestamp to reproduce a bug or inspect historical state.
Neon CLI Branch Commands
# Install the Neon CLI
npm install -g neonctl
# Authenticate
neonctl auth
# List existing branches
neonctl branches list --project-id
# Create a branch from the primary (latest WAL position)
neonctl branches create \
--project-id \
--name feature/my-feature
# Create a branch from a specific timestamp
neonctl branches create \
--project-id \
--name debug/investigate \
--parent-timestamp 2026-02-20T14:00:00Z
# Get the connection string for a branch
neonctl connection-string \
--project-id \
--branch feature/my-feature
# Delete a branch
neonctl branches delete feature/my-feature \
--project-id Store your branch connection strings in GitHub Actions secrets scoped to the PR environment. Use the Neon GitHub Actions integration (neondatabase/create-branch-action) to automate branch creation and deletion on PR open and close events.
GitHub Actions Integration for Preview Environments
name: Preview Environment
on:
pull_request:
types: [opened, synchronize, reopened, closed]
jobs:
setup-preview-db:
if: github.event.action != 'closed'
runs-on: ubuntu-latest
outputs:
db_url: ${{ steps.create-branch.outputs.db_url }}
steps:
- name: Create Neon branch
id: create-branch
uses: neondatabase/create-branch-action@v5
with:
project_id: ${{ vars.NEON_PROJECT_ID }}
branch_name: preview/pr-${{ github.event.pull_request.number }}
api_key: ${{ secrets.NEON_API_KEY }}
- name: Run migrations on branch
run: npx prisma migrate deploy
env:
DATABASE_URL: ${{ steps.create-branch.outputs.db_url }}
cleanup-preview-db:
if: github.event.action == 'closed'
runs-on: ubuntu-latest
steps:
- name: Delete Neon branch
uses: neondatabase/delete-branch-action@v3
with:
project_id: ${{ vars.NEON_PROJECT_ID }}
branch: preview/pr-${{ github.event.pull_request.number }}
api_key: ${{ secrets.NEON_API_KEY }}Autoscaling: Min/Max Compute Units
Neon measures compute in Compute Units (CU). One CU provides 1 vCPU and 4 GB of RAM. Autoscaling allows you to set a minimum and maximum CU value, and Neon adjusts the active compute between those bounds based on real-time demand.
// Neon API: update endpoint autoscaling configuration
{
"endpoint": {
"autoscaling_limit_min_cu": 0.25,
"autoscaling_limit_max_cu": 4,
"suspend_timeout_seconds": 300
}
}Fractional CU values (0.25, 0.5) are available, which makes Neon cost-effective for low-traffic databases. The autoscaler monitors CPU and memory pressure and scales up within seconds when load increases.
Scale to Zero and Cold Start Latency
When autoscaling_limit_min_cu is set to 0 (or suspend_timeout_seconds elapses with no activity), Neon suspends the compute endpoint entirely. No compute charges accrue while suspended. The tradeoff is a cold start: the first connection after suspension must wait for a new compute node to start and connect to the Pageserver. This typically takes 500ms to 1500ms.
Scale to zero is appropriate for development, staging, and low-traffic applications where occasional cold starts are acceptable. Do not enable it for latency-sensitive production endpoints. Set autoscaling_limit_min_cu to at least 0.25 for production workloads to keep the endpoint warm.
Connection Pooling with Built-in PgBouncer
Serverless functions open and close database connections on every invocation, which exhausts PostgreSQL's connection limit quickly. Neon addresses this by providing a built-in PgBouncer connection pooler at the platform layer. Each project has a pooled connection string in addition to the direct connection string.
# Direct connection (use for migrations, DDL, LISTEN/NOTIFY)
postgresql://user:pass@ep-quiet-forest-123456.us-east-2.aws.neon.tech/dbname
# Pooled connection (use for application queries)
postgresql://user:pass@ep-quiet-forest-123456-pooler.us-east-2.aws.neon.tech/dbname?pgbouncer=trueAlways use the pooled connection string for application servers and serverless functions. Use the direct connection string for schema migrations — PgBouncer in transaction mode does not support all session-level PostgreSQL features required by migration tools like Flyway or Liquibase.
Use Cases Where Neon Excels
- Development and staging environments — Instant branching from production data means developers always test against realistic data. No manual seeding scripts.
- Serverless and edge applications — Scale to zero and connection pooling are built for Next.js, Vercel, Cloudflare Workers, and similar runtimes.
- CI/CD pipelines — Each test run gets a fresh database branch. Parallel test suites run on isolated branches with no cross-contamination.
- SaaS with per-tenant databases — Neon's branching model maps naturally to per-tenant database isolation without per-tenant infrastructure overhead.
- Cost-sensitive side projects — The free tier and fractional CU pricing make Neon economical for low-traffic projects that would otherwise sit idle on a full instance.
Limitations to Know Before Adopting
- No logical replication as a subscriber (Free tier) — Logical replication is available on paid plans. The free tier does not support it.
- Cold start latency — Unavoidable when scale-to-zero is enabled. Mitigate with a warmer cron job or by keeping a minimum CU > 0.
- Single-region per project — Neon projects are deployed to a single region. Multi-region active-active is not supported; cross-region read replicas are available on paid plans.
- Network latency for reads — The Pageserver is remote. Co-locating your compute (Vercel region, AWS region) with the Neon region matters for performance.
- Storage history retention — WAL history retention (which determines how far back you can branch or time-travel) is limited to 7 days on the free tier and configurable up to 30 days on paid plans.
- Not ideal for heavy write OLAP — Neon is optimized for OLTP. For analytical workloads with heavy writes, dedicated OLAP systems are a better fit.
Neon vs. Supabase vs. PlanetScale
| Feature | Neon | Supabase | PlanetScale |
|---|---|---|---|
| Database engine | PostgreSQL | PostgreSQL | MySQL (Vitess) |
| Database branching | Yes (CoW, instant) | No | Yes (schema-only branches) |
| Scale to zero | Yes | Yes (free tier) | Yes |
| Storage-compute separation | Yes (core architecture) | Partial | Yes (Vitess) |
| Connection pooling | Built-in PgBouncer | Built-in PgBouncer | Built-in (PlanetScale proxy) |
| Extensions support | Most popular extensions | Broad extension support | Not applicable (MySQL) |
| Auth / storage included | No (database only) | Yes (full BaaS) | No (database only) |
| Open source | Yes (Apache 2.0) | Yes | Partially |
Neon wins on branching depth — PlanetScale branches are schema-only and do not copy data, while Neon branches include full data via CoW. Supabase includes more features out of the box (auth, storage, edge functions) but lacks branching. Choose Neon when the development workflow around database state is the primary concern.
Pricing Model
Neon bills on two dimensions independently: compute time and storage.
- Compute — Billed per CU-hour of active compute. A 0.25 CU endpoint costs roughly $0.0056/hour active. Suspended compute costs nothing.
- Storage — Billed per GB-month of stored data (including WAL history). Roughly $0.021/GB-month on the Launch plan.
- Free tier — 0.5 CU compute hours per month, 0.5 GB storage, up to 10 branches, 7-day WAL history. Sufficient for development and small side projects.
- Launch plan — $19/month flat, then usage-based above the included allowances. Suitable for production applications.
- Scale plan — $69/month, higher included compute, 30-day WAL history, read replicas.
Branch databases for CI/CD are typically short-lived (minutes to hours) and generate almost no storage divergence from the parent. In practice, dozens of daily PR branches add very little to the monthly bill — usually under a few dollars even on busy teams.
- Neon's storage-compute separation (Pageserver + Safekeeper architecture) is what makes instant branching and autoscaling possible — it is not a feature bolted on top of standard PostgreSQL.
- Database branches are copy-on-write clones created in milliseconds regardless of database size. They are the right tool for preview environments, CI pipelines, and destructive testing.
- The Neon CLI and GitHub Actions integration make branch lifecycle management scriptable with minimal configuration.
- Scale to zero eliminates idle compute cost but introduces cold start latency. Set a nonzero minimum CU for latency-sensitive production endpoints.
- Always use the pooled connection string (PgBouncer) for application traffic and the direct connection string for migrations.
- Neon is a database-only product. It does not include auth, storage, or other BaaS features — pair it with your existing infrastructure stack.
- Pricing is usage-based and transparent. The free tier is genuinely useful for development. Production workloads fit on the $19/month Launch plan in most cases.
Compare Neon Against Every Alternative on JusDB
Neon is a strong choice for PostgreSQL-first teams that want branching and serverless economics — but it is one of many options. JusDB maintains structured, up-to-date comparisons across Neon, Supabase, PlanetScale, CockroachDB, Turso, and every other major database provider. Filter by feature (branching, multi-region, edge support, pricing model) to find the right database for your specific workload without reading a dozen separate vendor docs. Visit JusDB to run the comparison.