TL;DR
Supabase for solo founders and small teams — you get PostgreSQL, auth, storage, and edge functions in one dashboard. Neon for teams that want pure serverless PostgreSQL with branching and minimal lock-in. PlanetScale when you want its managed Postgres infrastructure or MySQL-compatible Vitess for horizontal scaling and online schema changes. If you're starting fresh, compare Supabase's bundled backend, Neon's serverless Postgres workflow, and PlanetScale's engine-specific feature set before deciding.
Quick Comparison
| Feature | Supabase | Neon | PlanetScale |
|---|---|---|---|
| Database | PostgreSQL | PostgreSQL | PostgreSQL or MySQL-compatible Vitess |
| Free tier | 500MB + 50k rows | 0.5GB storage | None |
| Paid starts at | $25/mo | $19/mo | $5/mo (single-node Postgres) |
| Branching | ✅ (schema-level) | ✅ (git-like) | Engine-specific; Vitess includes Data Branching |
| Auth built-in | ✅ | ❌ | ❌ |
| Storage built-in | ✅ | ❌ | ❌ |
| Edge/serverless | ✅ Edge Functions | ✅ Serverless | ✅ |
| Row-level security | ✅ Built-in RLS | Postgres RLS | Available with the Postgres engine; not a Vitess feature |
| Realtime | ✅ Built-in | ❌ | ❌ |
| Lock-in | Medium (ecosystem) | Low (pure Postgres) | Low-to-medium depending on Postgres vs Vitess |
Supabase: The Full-Stack Postgres Platform
Supabase isn't just a database — it's auth, storage, edge functions, realtime, and database in one. The free tier is generous enough for side projects.
// Supabase client — one client for everything
import { createClient } from '@supabase/supabase-js';
const supabase = createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
);
// Auth
const { data: { user } } = await supabase.auth.signInWithOAuth({ provider: 'github' });
// Database query with RLS automatically enforced
const { data: posts } = await supabase
.from('posts')
.select('*, author(*)')
.eq('published', true)
.order('created_at', { ascending: false });
// File upload
const { data } = await supabase.storage
.from('avatars')
.upload(`${user.id}/avatar.png`, file);
// Realtime subscription
supabase
.channel('posts')
.on('postgres_changes', { event: 'INSERT', schema: 'public', table: 'posts' }, (payload) => {
console.log('New post:', payload.new);
})
.subscribe();
When Supabase Wins
- Solo founders and small teams who want one dashboard for everything
- Apps that need auth + database + storage tightly integrated
- Products that use Supabase's Row Level Security for multi-tenancy
- Teams coming from Firebase who want PostgreSQL power
- Projects where speed of development > infrastructure control
Supabase Limitations
- Free tier projects pause after 1 week of inactivity (not ideal for demos)
- Supabase ecosystem lock-in — if you use Supabase Auth + RLS + Realtime, migrating is painful
- Less control over PostgreSQL configuration vs raw Neon
- Edge Functions are Deno (not Node.js) — some npm packages don't work
Neon: Pure Serverless PostgreSQL
Neon focuses on one thing: serverless PostgreSQL with git-like branching. No auth, no storage, no extras. Just Postgres.
// Neon with Drizzle — no vendor lock-in in query code
import { drizzle } from 'drizzle-orm/neon-http';
import { neon } from '@neondatabase/serverless';
const sql = neon(process.env.DATABASE_URL!);
const db = drizzle(sql);
// Standard Drizzle/Prisma queries — database-agnostic
const users = await db.select().from(usersTable).where(eq(usersTable.active, true));
Neon Branching in Practice
Neon's killer feature: instant database branches. Every feature branch can have its own database state.
# Create a branch for a feature — instant, copy-on-write
neon branches create --name feature/new-billing-model --parent main
# Run migrations on branch without touching production
DATABASE_URL=$(neon connection-string feature/new-billing-model)
npx prisma migrate deploy
# Test in CI against the branch
# Merge PR → merge database branch → deploy to production
This is genuinely transformative for teams with complex migrations. No more "staging database is out of sync with production."
When Neon Wins
- Teams who want pure PostgreSQL with no lock-in
- Projects already using separate auth (Clerk, Auth.js) and storage (Cloudflare R2)
- Migration-heavy development where database branching pays off
- Edge-deployed apps (Neon's serverless driver works in Cloudflare Workers, Vercel Edge)
- Developers who want to self-host later — Neon is standard Postgres
Neon Limitations
- No auth, storage, or realtime built-in — you assemble these separately
- Free tier is smaller than Supabase (0.5GB vs Supabase's 500MB + auth + storage)
- Compute autoscales to zero — cold starts when inactive (50-200ms)
PlanetScale: Managed Postgres or Vitess
PlanetScale now offers two engines on its self-serve Base plan: Postgres and Vitess, the MySQL-compatible clustering technology associated with YouTube-scale workloads. Vitess supplies the non-blocking schema-change and Data Branching workflow described below; PlanetScale Postgres instead emphasizes managed Postgres, PgBouncer connection pooling, traffic controls, and independently billed branch clusters.
The Key Differentiator: Non-Blocking Migrations
-- Regular MySQL: ALTER TABLE locks the entire table
-- On a large table, this can take hours and block all queries
ALTER TABLE users ADD COLUMN subscription_tier VARCHAR(20);
-- PlanetScale: deploy requests handle this transparently
-- Schema changes are applied without locking
-- Works with tables of billions of rows
When PlanetScale Wins
- Teams that want managed Postgres with PlanetScale's infrastructure and traffic controls
- Teams with MySQL experience that need Vitess horizontal sharding
- Products that need Vitess deploy requests and online schema changes
- Workloads where the selected engine's scaling and availability model justify the cost
PlanetScale Limitations
- No free plan; the $5 entry price is a single-node Postgres configuration, not high availability
- Features differ by engine: Data Branching and current horizontal sharding are Vitess features, while Postgres uses the Postgres ecosystem
- Vitess foreign-key constraints must be enabled and have documented limitations, especially for sharded environments
- Existing boilerplates may require driver, migration, or schema-tooling changes when switching engines
Which Boilerplates Use What
| Boilerplate | Database | Notes |
|---|---|---|
| ShipFast | Supabase or MongoDB | Supabase version most popular |
| Supastarter | Supabase | RLS-based multi-tenancy |
| Makerkit | Supabase | Supabase-first, Postgres option |
| T3 Stack | PostgreSQL (any) | Usually Neon or Supabase Postgres |
| Epic Stack | SQLite + Fly / PostgreSQL | Starts SQLite, scales to Postgres |
Decision Framework
Need auth + storage + realtime in one platform?
→ Supabase
Want pure Postgres with git-like branching and no ecosystem lock-in?
→ Neon
MySQL team or need schema changes on tables with billions of rows?
→ PlanetScale
Starting small, want the simplest setup?
→ Supabase (most batteries included) or Neon (simplest pricing)
Schema Migration Workflows in Practice
How you manage schema changes in production is where these three databases diverge most sharply in day-to-day development experience.
With Supabase, the standard workflow uses the Supabase CLI to generate and apply migrations. Running supabase db diff --schema public compares your local schema against the remote and generates a SQL migration file. You commit that file to version control and apply it to production with supabase db push. The Supabase dashboard also has a table editor that auto-generates migrations when you add columns via GUI — useful for prototyping but dangerous in production because it bypasses your migration history.
Neon's branching feature transforms migration workflows. Before applying a potentially destructive migration, you create a branch (neon branches create --name migration-test), run the migration against the branch, and test with production-equivalent data. If something breaks, you delete the branch and no production data was touched. This is genuinely transformative for migrations that add NOT NULL constraints, rename columns, or drop tables — operations that are safe to test but risky to deploy blind. Teams with weekly migration cadences report it eliminates the pre-migration anxiety that slows deploys.
PlanetScale's deploy requests take migration safety furthest. Rather than applying migrations directly, you open a "deploy request" — similar to a pull request but for schema changes. PlanetScale analyzes the migration for blocking operations, estimates downtime, and shows you the diff. A team member reviews and approves. The schema change deploys without locking tables, regardless of the table size. For B2B SaaS with enterprise SLAs, schema changes without maintenance windows are worth the MySQL constraint.
The tradeoff is real: PlanetScale's non-blocking migrations require foreign key constraints to be handled in application logic rather than enforced by the database. Prisma has historically had issues with this (the relationMode = "prisma" config). Neon and Supabase use standard PostgreSQL foreign keys enforced by the database. Teams migrating from Rails or Laravel to Prisma+PlanetScale often hit this friction early.
Connection Pooling and Serverless Compatibility
Serverless functions create a database connection problem that traditional hosted databases weren't designed to handle.
A standard PostgreSQL server handles 100–500 concurrent connections before performance degrades. A serverless deployment can create hundreds of simultaneous function instances, each wanting its own connection — far exceeding database limits. Without a pooler, your app crashes under load with "too many connections" errors.
Supabase includes PgBouncer (a connection pooler) at the platform level. Your Prisma configuration needs two connection strings: DATABASE_URL (pooled, for application queries) and DIRECT_URL (direct, for migrations). The pooled URL routes through PgBouncer which multiplexes many application connections onto fewer database connections. Supabase handles the pooler configuration — you just use the right URL.
Neon's architecture is serverless-native. The Neon serverless driver (@neondatabase/serverless) uses HTTP rather than persistent TCP connections, which means each query is a stateless HTTP request. There are no connection limits to exhaust. This design is the reason Neon works in Cloudflare Workers and Vercel Edge Functions where persistent TCP connections are impossible. For Drizzle users, this is the key reason drizzle-orm/neon-http is the recommended adapter over drizzle-orm/node-postgres.
PlanetScale's @planetscale/database HTTP driver applies to Vitess/MySQL workflows. PlanetScale Postgres uses standard Postgres clients and offers PgBouncer-based connection pooling, so choose the driver and ORM adapter for the engine you actually create.
The practical recommendation: if you're deploying to Vercel or Cloudflare Workers, Neon's HTTP driver is the most ergonomic choice. If you're on a persistent server (Railway, Render, traditional VPS), standard PostgreSQL connections via Prisma/Drizzle work fine with Supabase, and connection pooling via PgBouncer becomes relevant only when your connection count grows.
Pricing at Scale: What Changes When You Grow
The free tiers all look similar at zero. The gap opens at meaningful scale.
Supabase's Pro plan at $25/month includes 8GB storage, 50K MAU for Auth, 100GB egress, and 500GB-hours of compute. The compute autoscaling is the key variable — a database that handles steady load cheaply can spike in cost during traffic bursts if you haven't provisioned appropriately. The $25 flat rate covers a typical early-stage SaaS comfortably. Beyond that, Supabase bills per additional compute, storage, and egress.
Neon's Launch tier at $19/month provides 10GB storage and 300 compute hours (enough for a production app that doesn't run 24/7). The autoscaling-to-zero feature means you pay only for active compute — important for staging and development environments that run intermittently. Neon's pricing is compute-unit based; a database with bursty traffic but low baseline load often runs cheaper on Neon than on a fixed-allocation service.
PlanetScale removed its free tier in 2024, but its current Base plan offers both Postgres and MySQL-compatible Vitess. Single-node Postgres starts at $5/month, and the entry highly available Postgres configuration starts at $15/month; Vitess and larger Postgres clusters are priced by cluster size, region, storage, and configuration. Treat $5 as a development or non-critical starting point, not the total for a production HA deployment, and verify the live calculator before choosing.
Multi-Tenancy Patterns: How Each Database Handles B2B SaaS
B2B SaaS applications face a structural challenge that consumer apps don't: multiple customers (tenants) share the same database infrastructure, but their data must be isolated, queryable, and manageable independently.
Supabase and Row Level Security offer the most elegant multi-tenancy story. Each row in a shared table includes an organization_id column. RLS policies attached to the table ensure that any query automatically filters to the current user's organization — no application-level WHERE clauses needed. The policy runs inside the database engine, meaning it's enforced even if your application code is buggy. For a boilerplate like Supastarter or Makerkit, which target multi-tenant B2B SaaS, this is the reason Supabase is the obvious default.
-- Create organization isolation with a single RLS policy
CREATE POLICY "org_isolation" ON projects
USING (organization_id = (
SELECT organization_id FROM memberships
WHERE user_id = auth.uid()
));
Once this policy exists, every query against projects — from the Supabase client, from Prisma, from raw SQL in a Supabase Edge Function — automatically scopes to the authenticated user's organization. This is a meaningful DX advantage for boilerplates that need multi-tenancy on day one.
Neon's approach to multi-tenancy is standard PostgreSQL: you handle tenant isolation in application code or via Postgres schemas. The more advanced pattern — one Postgres schema per tenant — works well on Neon because schema creation is cheap and branching lets you test schema migrations per-tenant before deploying to all tenants. Neon's branching model can mirror your multi-tenant schema structure: one branch per major tenant for migration testing.
PlanetScale depends on the selected engine. PlanetScale Postgres can use standard Postgres isolation patterns, including RLS where your schema and client context are designed for it. Vitess uses MySQL-compatible patterns; sharded or constraint-light designs can place more isolation responsibility in application code. Evaluate multi-tenancy against the engine, not the PlanetScale brand alone.
Backup, Recovery, and Data Durability
Operational databases need reliable backup and point-in-time recovery. Here's how the three services differ:
Supabase Pro and above includes daily backups with 7-day retention and point-in-time recovery (PITR) — the ability to restore your database to any second within the retention window. PITR requires the $25/month Pro tier; the free tier only gets daily snapshots. For a production SaaS, PITR is a hard requirement: if a bug deploys and corrupts data, you need to restore to exactly before the bad deploy, not to yesterday's backup.
Neon's architecture makes backup almost trivially simple. Because Neon's storage layer is copy-on-write and branching is instant, you can create a "backup branch" at any moment in seconds. Neon also supports PITR — you can restore a branch to any historical point. For development workflows, this matters enormously: before running a risky migration, create a branch, run the migration on the branch, validate, then apply to production. If production migration fails, your data is untouched.
PlanetScale's Base plan documentation lists automatic backups every 12 hours for both engines, while restore and retention details depend on the product and configuration. Vitess deploy requests add review to schema changes, but review is not a substitute for backups or restore testing.
The practical guidance: all three offer acceptable backup and recovery for production SaaS. Neon's branch-based workflow makes pre-migration snapshots genuinely frictionless, which reduces the anxiety of schema migrations more than any backup feature does.
Compare boilerplates by database provider on StarterPick.
See the Drizzle vs Prisma guide for ORM-specific database compatibility considerations.
Review the database-ready SaaS boilerplates guide — most are pre-configured for either Supabase or Neon.
Exploring your full tech stack? The Next.js SaaS tech stack guide covers how database choice fits into the broader SaaS architecture decision.
