What Is Neon and Why Serverless Postgres?
Neon is a fully managed, serverless PostgreSQL platform that separates storage and compute. Unlike traditional hosted Postgres, Neon doesn’t require you to provision or manage servers. Compute resources scale down to zero when idle — meaning you only pay (or consume free-tier credits) when your database is actually running queries.
Why does this matter?
Traditional Postgres hosting charges you 24/7 for a running instance, even if nobody is hitting your database at 3 AM. Neon’s architecture eliminates that waste. For developers, this translates to:
- No idle cost. Compute auto-suspends after inactivity.
- Instant branching. Copy your entire database — schema and data — in seconds using copy-on-write storage.
- True PostgreSQL. It’s not a Postgres-compatible wrapper. It is PostgreSQL 16, with full extension support.
- Built-in connection pooling. Neon uses its own WebSocket-based proxy with pooled connections out of the box.
If you’ve ever hesitated to spin up a Postgres instance for a side project because of cost or overhead, Neon’s free tier removes that friction entirely.
Neon Free Tier: Key Features and Limits
Neon’s free plan (called the Launch plan) is generous enough for prototyping, learning, and small production workloads. Here’s what you get:
| Resource | Free Tier Limit |
|---|---|
| Storage | 500 MB |
| Compute | 100 compute-hours/month |
| Branches | Up to 3 |
| Databases per project | Unlimited |
| Projects | 1 |
| Max connections | 100 (via pooled connection string) |
| Point-in-time restore | 7 days of history |
| Autosuspend | After 5 minutes of inactivity |
The Branching Feature
The killer feature of Neon is database branching. A branch is a full copy of your database (schema + data) that is created instantly using copy-on-write semantics. It doesn’t duplicate storage — new data written to the branch is the only storage that gets added.
This means you can:
- Branch
main→dev-feature-authin under a second - Test destructive migrations against a real copy of production data
- Run integration tests on isolated branches and delete them afterward
- Each branch has its own connection string
On the free tier, you can have up to 3 branches simultaneously, each with its own compute endpoint that can suspend independently.
Best Use Cases (With Real Examples)
Branching for Development and Testing
The most impactful use case is replacing your single shared dev database with per-developer or per-feature branches.
Real scenario: You’re building a REST API with Express.js and need to add a new invoices table with a migration. Instead of running the migration on your shared dev database and hoping nobody else is affected:
main (production data snapshot)
├── dev-invoices-feature ← your branch
├── dev-auth-refactor ← teammate's branch
└── test-ci-4872 ← ephemeral CI branch
Each branch has full production-like data. You test your migration, validate queries, and merge with confidence.
CI/CD Integration
Neon’s branching API is tailor-made for CI/CD pipelines. You can script branch creation and teardown directly in your GitHub Actions or GitLab CI workflow.
Example GitHub Actions step:
- name: Create Neon branch for tests
run: |
BRANCH=$(curl -s -X POST "https://console.neon.tech/api/v2/projects/${PROJECT_ID}/branches" \
-H "Authorization: Bearer $NEON_API_KEY" \
-H "Content-Type: application/json" \
-d '{"branch": {"name": "ci-run-${{ github.run_id }}", "parent_id": "br-main-branch-id"}}' \
| jq -r '.branch.id')
echo "NEON_BRANCH=$BRANCH" >> $GITHUB_ENV
- name: Run integration tests
run: npm test
env:
DATABASE_URL: ${{ secrets.NEON_BRANCH_URL }}
- name: Delete branch
if: always()
run: |
curl -X DELETE "https://console.neon.tech/api/v2/projects/${PROJECT_ID}/branches/${NEON_BRANCH}" \
-H "Authorization: Bearer $NEON_API_KEY"
Your tests run against a real Postgres instance with production data, and the branch is deleted after the pipeline completes — no storage bloat.
Other Strong Use Cases
- Side projects and hackathons — zero cost for a real Postgres database.
- Learning SQL — full Postgres with extensions like
pg_trgm,uuid-ossp, andpgcrypto. - Preview environments — pair with Vercel or Netlify preview deploys; each PR gets its own database branch.
- Lightweight production — small apps, blogs, or internal tools that receive moderate traffic.
Step-by-Step Setup Guide
Step 1: Sign Up for Neon
- Go to neon.tech.
- Click Sign Up — you can use GitHub, Google, or email.
- You’ll land on the Neon Console dashboard.
No credit card is required for the free tier.
Step 2: Create a Project
After signing up, Neon automatically creates your first project with a main branch. You can also create additional projects from the dashboard (note: the free tier allows only 1 project).
Your default project comes with:
- A
mainbranch - A default database (usually
neondb) - A role (usually
neondb_owner)
Step 3: Get Your Connection String
- In the Neon Console, click on your project.
- Go to the Dashboard tab and find the Connection Details widget.
- Select Pooled connection string (recommended for most applications).
You’ll see something like:
postgresql://neondb_owner:***@ep-cool-bird-123456.us-east-2.aws.neon.tech/neondb?sslmode=require
Neon also provides a direct connection string (for long-running transactions or tools that don’t work well with pooling) and a WebSocket URL (for serverless environments like Cloudflare Workers).
Step 4: Connect with psql
Open your terminal and connect using the pooled connection string:
psql "postgresql://neondb_owner:***@ep-cool-bird-123456.us-east-2.aws.neon.tech/neondb?sslmode=require"
You should see the standard psql prompt:
psql (16.2, server 16.2)
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384)
Type "help" for help.
neondb=>
Step 5: Create a Table and Insert Data
Let’s set up a simple schema:
CREATE TABLE todos (
id SERIAL PRIMARY KEY,
title TEXT NOT NULL,
completed BOOLEAN DEFAULT FALSE,
created_at TIMESTAMPTZ DEFAULT NOW()
);
INSERT INTO todos (title) VALUES
('Set up Neon database'),
('Build the API'),
('Deploy to production');
SELECT * FROM todos;
id | title | completed | created_at
----+------------------------+-----------+-------------------------------
1 | Set up Neon database | f | 2025-01-20 14:32:01.234567+00
2 | Build the API | f | 2025-01-20 14:32:01.234567+00
3 | Deploy to production | f | 2025-01-20 14:32:01.234567+00
(3 rows)
Step 6: Create a Branch for Development
Now branch your database for a new feature:
Option A — Neon Console:
- Go to the Branches tab in your project.
- Click Create Branch.
- Name it
dev-add-due-dates. - Select
mainas the parent. - Click Create.
Option B — Neon CLI:
# Install the CLI if you haven't
npm install -g neonctl
# Create a branch
neon branches create --name dev-add-due-dates --project-id your-project-id
Option C — API:
curl -X POST "https://console.neon.tech/api/v2/projects/your-project-id/branches" \
-H "Authorization: Bearer $NEON_API_KEY" \
-H "Content-Type: application/json" \
-d '{"branch": {"name": "dev-add-due-dates", "parent_id": "br-main-branch-id"}}'
Once the branch is created, grab its connection string from the Console (each branch gets its own compute endpoint). Connect and test your migration safely:
psql "postgresql://neondb_owner:***@ep-dev-branch-789012.us-east-2.aws.neon.tech/neondb?sslmode=require"
-- Test the migration on the branch
ALTER TABLE todos ADD COLUMN due_date DATE;
SELECT * FROM todos;
-- The 3 existing rows are here — copied from main via copy-on-write
Once satisfied, run the migration on main and delete the dev branch to free up resources.
How Neon Compares to Alternatives
Neon vs. Supabase
| Feature | Neon (Free Tier) | Supabase (Free Tier) |
|---|---|---|
| Storage | 500 MB | 500 MB |
| Compute | 100 compute-hours/month | Always-on (shared) |
| Branching | ✅ Full branching with copy-on-write | ❌ No database branching |
| Auth / Storage / Edge Functions | ❌ Database only | ✅ Full BaaS platform |
| Connection pooling | Built-in (PgBouncer-based) | Built-in (Supavisor) |
| Auto-suspend | ✅ Yes (5 min idle) | ❌ Hibernates after 7 days inactive |
| Point-in-time restore | 7 days | 7 days (Pro plan) |
Choose Supabase if you need an all-in-one backend (auth, file storage, real-time subscriptions, edge functions). Choose Neon if you want a pure, best-in-class Postgres experience with branching and don’t need the extra BaaS features.
Neon vs. PlanetScale
| Feature | Neon (Free Tier) | PlanetScale (Free Tier) |
|---|---|---|
| Database engine | PostgreSQL | MySQL (Vitess-based) |
| Storage | 500 MB | 5 GB |
| Branching | ✅ Yes | ✅ Yes |
| Schema migrations | Standard Postgres migrations | Non-blocking schema changes |
| Always-on | No (auto-suspend) | Yes |
| Foreign keys | ✅ Full support | ❌ Limited (Vitess limitation) |
| Free tier status | Active | Discontinued for new signups |
Choose Neon if you need PostgreSQL specifically — full foreign key support, JSONB, advanced extensions, and the broader Postgres ecosystem. PlanetScale’s MySQL/Vitess approach has limitations (no foreign keys, no ALTER TABLE in the traditional sense), and their free tier is no longer available to new users.
Tips to Maximize the Free Tier
1. Delete Stale Branches Aggressively
Every branch with a compute endpoint counts toward your 3-branch limit. If you create branches for feature work or CI runs, delete them when done:
# List all branches
neon branches list --project-id your-project-id
# Delete a specific branch
neon branches delete --branch-id br-branch-id --project-id your-project-id
In CI, always use a cleanup step (see the GitHub Actions example above) to delete ephemeral branches even if tests fail.
2. Set Aggressive Autosuspend Times
In your project settings, set the autosuspend timeout to 1 minute (the minimum). This ensures compute hours aren’t wasted when you step away:
Settings → Compute → Suspend after 1 minute of inactivity
Your first query after suspension will take 500ms–2s to wake the compute endpoint. This is a worthwhile trade-off for free-tier savings.
3. Monitor Compute Hours in the Dashboard
The Neon Console shows real-time compute usage under the Usage tab. Check this weekly to understand your patterns:
- A single branch running 24/7 uses ~720 hours/month — you’ll run out fast.
- A branch that suspends after 1 minute of idle uses far less — typically 20–50 hours/month for a development workflow.
- If you’re close to the limit, reduce the number of active branches or consolidate compute to fewer endpoints.
4. Use Manual Exports for Backups
Neon provides 7-day point-in-time restore, but for extra safety or data portability, export your data periodically:
pg_dump "postgresql://neondb_owner:***@ep-cool-bird-123456.us-east-2.aws.neon.tech/neondb?sslmode=require" \
-F custom -f backup_$(date +%Y%m%d).dump
Store the dump file locally or in object storage. This also lets you restore data to other Postgres providers if needed.
5. Use the Direct Connection String Wisely
The pooled connection string is great for applications (limits to 100 connections via PgBouncer). But for long-running operations like large data imports or pg_dump, switch to the direct connection string to avoid pooling timeouts:
# Direct (non-pooled) connection string
postgresql://neondb_owner:***@ep-cool-bird-123456.us-east-2.aws.neon.tech/neondb?sslmode=require
The pooled endpoint uses a -pooler suffix in the hostname. Make sure you’re using the right one for the job.
6. Leverage the Neon Serverless Driver
If you’re deploying on edge runtimes (Vercel Edge Functions, Cloudflare Workers) where TCP connections aren’t available, use Neon’s serverless driver instead of a traditional Postgres client:
npm install @neondatabase/serverless
import { neon } from '@neondatabase/serverless';
const sql = neon(process.env.DATABASE_URL);
const todos = await sql`SELECT * FROM todos WHERE completed = false`;
This driver communicates over HTTP/WebSocket and is optimized for serverless cold starts.
