I've used Supabase, PlanetScale, Railway, and plain RDS. For most of my projects today, I reach for Neon first — and the reason is feature that sounds gimmicky until you actually use it: database branching.
Let me explain what it is and why it matters in practice.
What is Neon?
Neon is serverless Postgres. Not "Postgres-compatible" — it's actual PostgreSQL, with a twist: compute and storage are separated. Your database scales to zero when idle (you're not paying for a sleeping database), and spins up in milliseconds when a query arrives.
The connection string looks exactly like any other Postgres connection:
postgresql://user:password@ep-cool-name-123456.us-east-2.aws.neon.tech/mydb
Existing Postgres tooling — SQLAlchemy, Prisma, Drizzle, psycopg2 — works without modification.
Database Branching
This is the killer feature. A branch in Neon is a full copy-on-write fork of your database, created instantly regardless of database size. Zero data copying — Neon uses the same underlying storage pages and diverges only as writes occur.
# Neon CLI
neon branches create --name preview/pr-142 --parent main
This creates a branch with a complete snapshot of production data (or staging) in under a second. Your PR gets its own isolated database environment.
Preview Deployments with Real Data
The workflow I use with Vercel previews:
1. GitHub Action creates a Neon branch on PR open:
- name: Create Neon branch
id: neon
uses: neondatabase/create-branch-action@v5
with:
project_id: ${{ secrets.NEON_PROJECT_ID }}
branch_name: preview/pr-${{ github.event.number }}
api_key: ${{ secrets.NEON_API_KEY }}
- name: Deploy to Vercel with branch DB
run: vercel deploy --env DATABASE_URL=${{ steps.neon.outputs.db_url }}
2. Migrations run against the branch, not production:
# Safe — runs on the isolated preview branch
DATABASE_URL=$PREVIEW_DB_URL npx prisma migrate deploy
Now each PR has its own database. A migration that breaks data? It's isolated to that PR's branch. You catch it in code review before it ever touches production.
3. Branch is deleted when PR is merged:
- name: Delete Neon branch
if: github.event.action == 'closed'
uses: neondatabase/delete-branch-action@v3
with:
project_id: ${{ secrets.NEON_PROJECT_ID }}
branch: preview/pr-${{ github.event.number }}
This is the workflow I wish every team had when running migrations in the dark and hoping for the best.
Scale to Zero in Practice
Serverless databases have a reputation for cold-start latency. Neon's connection pooling via pgbouncer (built-in at the connection string level) eliminates most of this:
# Use the pooled connection string for app servers
postgresql://user:password@ep-cool-name-123456-pooler.us-east-2.aws.neon.tech/mydb
For low-traffic projects, I configure the auto-suspend timeout to 5 minutes. The database stays warm during active use; sleeps during off-hours. On the free tier, this easily handles side-projects with no infra cost.
When NOT to Use Neon
Neon is not right for every situation:
- High-throughput OLAP — use Snowflake or ClickHouse; Neon is optimized for OLTP
- Very large datasets — storage costs at scale aren't free; check pricing beyond 10GB
- Compliance-heavy — if you need specific data residency guarantees, verify region availability
For greenfield web apps, SaaS products, and internal tools? Neon is an excellent default.
Getting Started
# Install Neon CLI
npm i -g neonctl
# Authenticate
neonctl auth
# Create a project (free tier, no credit card)
neonctl projects create --name my-app
# Get the connection string
neonctl connection-string
Five minutes to a production-ready serverless Postgres. Give it a try on your next side project.