Serverless Postgres — scales to zero when idle, instant branching for dev environments, generous free tier. Sign up, copy the connection string, ship. Five minutes to a real database.
Sign up at console.neon.tech ↗. Free; GitHub or Google OAuth.
Create a project:
neondb is fine.Provisioning takes ~5 seconds (one of Neon's tricks — Postgres copy-on-write from a base image).
Project dashboard shows the connection string immediately. Format:
postgresql://<user>:<password>@ep-xxxxxx.region.aws.neon.tech/neondb?sslmode=require
Copy it. Store in your backend env:
DATABASE_URL=postgresql://user:[email protected]/neondb?sslmode=require
Two connection modes:
-pooler suffix; for serverless functions / edge runtimes where you can't hold a long-lived connection. Use this from Vercel, Cloudflare Workers, AWS Lambda.Neon's dashboard has a "Connection string" panel with both modes; copy the one that matches your runtime.
Any Postgres library works — it's plain Postgres. Two common patterns:
Traditional server (Node + pg):
npm install pg
import { Pool } from "pg";
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
const { rows } = await pool.query("SELECT * FROM users WHERE id = $1", [123]);
Serverless / edge (Neon's HTTP driver — no TCP):
npm install @neondatabase/serverless
import { neon } from "@neondatabase/serverless";
const sql = neon(process.env.DATABASE_URL);
const users = await sql`SELECT * FROM users WHERE id = ${123}`;
The HTTP driver works in Cloudflare Workers, Vercel Edge Functions, and other places traditional TCP-based Postgres clients can't run. Neon serverless driver docs ↗.
Option A — Neon SQL Editor: dashboard → SQL Editor. Paste:
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email TEXT NOT NULL UNIQUE,
created_at TIMESTAMPTZ DEFAULT now()
);
Click run.
Option B — your own ORM: any standard tooling works since this is just Postgres. Common picks:
Define your schema however you like; run migrations against the Neon URL.
Neon's branches are like git branches — copy-on-write snapshots of your database at any point in time. Take a branch, run migrations against it, throw it away if it's wrong.
Dashboard → Branches → Create branch. New branch is ready in seconds; gets its own connection string.
Use cases:
Neon doesn't impose a migration tool — use whatever you like:
drizzle-kit generate + drizzle-kit migrate. Generates SQL from TypeScript schema.prisma migrate dev / prisma migrate deploy.psql.The Neon branching pattern shines for migration safety: branch first, run the migration on the branch, verify it worked, then apply to main.
If you're on a serverless runtime (Vercel, Cloudflare Workers, AWS Lambda), use the pooled connection string:
postgresql://user:[email protected]/neondb?sslmode=require
The -pooler suffix routes through Neon's connection pooler. Without it, each cold-start opens a new connection; you hit Postgres's connection limit fast.
Note: pooled connections don't support session-level features (advisory locks, SET statements that should persist, prepared statements). Use direct connection if you need those, with your own pool (e.g., pgBouncer).
Free tier: 24-hour history (you can branch from any point in the last day). Paid tiers extend history to 7 days, 30 days, or longer.
To "restore from backup," you branch from a previous timestamp and re-point your app at that branch's connection string. Faster than traditional dump/restore.
Manual backups via pg_dump still work for archival to S3 / cold storage. Run on a cron.
Dashboard → Monitoring. Shows:
For deeper observability — slow query log, index usage stats — enable pg_stat_statements ↗ and run standard Postgres performance queries against it.
Free tier: 0.5 GB storage, 24-hour point-in-time recovery, 10 projects. Real for early stage.
Launch tier: $19/mo — 10 GB storage, 7-day PITR. Pro tier: $69/mo — 50 GB, 30-day PITR, autoscaling. Neon pricing ↗.
Compute usage billed separately past free tier; scale-to-zero keeps idle costs near zero.