Neon Free Tier — Best Use Cases, Setup Guide & Alternatives

Neon Free Tier — Best Use Cases, Setup Guide & Alternatives

Learn how to build with Neon's free serverless PostgreSQL tier — 500MB storage, branching, CI/CD integration, and a practical step-by-step setup guide.

PostgreSQLServerlessDatabaseNeonFree TierDevOps

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 maindev-feature-auth in 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, and pgcrypto.
  • 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

  1. Go to neon.tech.
  2. Click Sign Up — you can use GitHub, Google, or email.
  3. 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 main branch
  • A default database (usually neondb)
  • A role (usually neondb_owner)

Step 3: Get Your Connection String

  1. In the Neon Console, click on your project.
  2. Go to the Dashboard tab and find the Connection Details widget.
  3. 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:

  1. Go to the Branches tab in your project.
  2. Click Create Branch.
  3. Name it dev-add-due-dates.
  4. Select main as the parent.
  5. 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.