Skip to main content

Turso vs PlanetScale vs Neon: Serverless Databases for TypeScript 2026

·PkgPulse Team

Databricks acquired Neon in early 2026 and cut compute costs 15-25%. PlanetScale killed its free tier in 2024 but remains the reliability benchmark for MySQL-based SaaS. Turso replicates SQLite to edge locations globally, cutting read latency by up to 90% for distributed applications. These aren't the same database in different wrappers — they're distinct architectural choices with different tradeoffs on cost, latency, and scale.

TL;DR

Neon for serverless Postgres with a free tier, schema branching, and scale-to-zero — the default choice for new TypeScript projects on Postgres. PlanetScale for production MySQL workloads where uptime guarantees matter more than free tier savings. Turso when SQLite at the edge fits your workload: read-heavy apps, multi-tenant databases, or Cloudflare Workers deployments. For most new applications in 2026, Neon is the pragmatic starting point.

Key Takeaways

  • Neon: Serverless Postgres, free tier (100 compute-hours/month, 0.5 GB), acquired by Databricks 2026
  • PlanetScale: No free tier since April 2024; plans from $39/month (Scaler Pro)
  • Turso: SQLite + libSQL, free tier (9 GB, 500 databases), $4.99/month Developer plan
  • Neon: Schema branching like Git branches for your database — dev/staging/PR environments
  • PlanetScale: Database branching, non-blocking schema changes, MySQL compatibility
  • Turso: Edge replicas reduce read latency by up to 90%; works on Cloudflare Workers natively
  • All three have TypeScript SDKs and work with Drizzle, Prisma, and raw SQL clients

The Serverless Database Landscape

Traditional databases run on dedicated servers. Serverless databases add:

  • Scale-to-zero: The database pauses when idle (reducing costs for low-traffic apps)
  • Connection pooling: Managed by the platform (no PgBouncer setup)
  • Branching: Database schema branches for development environments
  • Edge proximity: Replicas close to users for lower latency

The tradeoff: cold starts on serverless databases add latency after periods of inactivity.

Neon

Type: Serverless PostgreSQL GitHub stars: 16K (neon repo) Creator: Neon Inc. (acquired by Databricks, Jan 2026)

Neon is purpose-built serverless Postgres. It separates compute from storage, enabling true scale-to-zero — the database pauses when idle and resumes in ~300ms on the next connection.

Connection

import { neon } from '@neondatabase/serverless';

const sql = neon(process.env.DATABASE_URL!);

// Executes a query against your Neon database
const users = await sql`SELECT * FROM users WHERE active = true`;

With Drizzle ORM

import { drizzle } from 'drizzle-orm/neon-http';
import { neon } from '@neondatabase/serverless';
import { users } from './schema';

const sql = neon(process.env.DATABASE_URL!);
const db = drizzle(sql);

const activeUsers = await db
  .select()
  .from(users)
  .where(eq(users.active, true));

With Prisma

// schema.prisma
datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}
import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient();
// Works with Neon out of the box
const users = await prisma.user.findMany({ where: { active: true } });

Neon Branching

Neon's killer feature: database branches for development environments.

# Install Neon CLI
npm install -g neonctl

# Create a branch for a feature (copies production data)
neonctl branch create --name feature/user-auth --parent main

# Use branch in dev environment
neonctl connection-string feature/user-auth
# postgres://user:pass@ep-xxx.us-east-2.aws.neon.tech/main?sslmode=require

# Delete branch when done
neonctl branch delete feature/user-auth

This enables pull-request-level database environments: each PR gets its own database branch with a copy of the schema (and optionally data), so developers test schema changes safely.

Neon Pricing (2026)

PlanComputeStoragePrice
Free100 compute-hours/month0.5 GB (5 GB across projects)Free forever
LaunchAutoscaling 0.25-4 CU10 GB~$19/month
ScaleAutoscaling 0.25-8 CU50 GB~$69/month

Databricks' 2026 acquisition cut compute costs 15-25% across all tiers.

Neon Limitations

  • Cold starts: ~300ms latency after idle periods
  • PostgreSQL only (no MySQL or SQLite)
  • Maximum database size limits on lower tiers
  • Scale-to-zero can surprise users with first-request latency

PlanetScale

Type: Serverless MySQL (Vitess-based) Creator: PlanetScale Inc. Technology: Vitess (powers YouTube's MySQL at scale)

PlanetScale uses Vitess — the MySQL sharding infrastructure built at YouTube and used by GitHub, Slack, and Square. It offers MySQL compatibility with horizontal scaling built in.

Connection

import { connect } from '@planetscale/database';

const conn = connect({
  host: process.env.DATABASE_HOST,
  username: process.env.DATABASE_USERNAME,
  password: process.env.DATABASE_PASSWORD,
});

const results = await conn.execute('SELECT * FROM users WHERE active = ?', [true]);
console.log(results.rows);

With Drizzle ORM

import { drizzle } from 'drizzle-orm/planetscale-serverless';
import { connect } from '@planetscale/database';
import { users } from './schema';

const connection = connect({
  host: process.env.DATABASE_HOST,
  username: process.env.DATABASE_USERNAME,
  password: process.env.DATABASE_PASSWORD,
});

const db = drizzle(connection);
const activeUsers = await db
  .select()
  .from(users)
  .where(eq(users.active, true));

PlanetScale Branching (Non-Blocking Schema Changes)

PlanetScale's original innovation: schema changes via deploy requests that don't lock tables.

# PlanetScale CLI
pscale branch create mydb add-user-avatar
pscale shell mydb add-user-avatar

# In the SQL shell:
ALTER TABLE users ADD COLUMN avatar_url VARCHAR(500);

# Open a deploy request (like a pull request for schema changes)
pscale deploy-request create mydb add-user-avatar

# Merge the schema change without table locking
pscale deploy-request deploy mydb 1

PlanetScale's foreign key constraint tradeoff: by default, PlanetScale disables foreign key constraints (referential integrity is handled at the application level) to enable horizontal sharding. Some teams find this acceptable; others don't.

PlanetScale Pricing (2026)

PlanPriceIncludes
PS-10 (single node)$5/month1 primary, limited
Scaler Pro$39/monthAutoscaling, branching, support
EnterpriseCustomMulti-region, SLA

No free tier since April 2024. The $5/month single-node plan is limited and not suitable for production.

PlanetScale Strengths

  • Production reliability track record (Vitess powers YouTube, GitHub, Slack)
  • Non-blocking schema changes (no table locks during ALTER TABLE)
  • MySQL compatibility: migrate existing MySQL applications with minimal changes
  • Horizontal scaling built-in for multi-tenant SaaS

PlanetScale Limitations

  • No free tier (significant disadvantage vs Neon and Turso for exploration)
  • MySQL only (no Postgres)
  • Foreign keys disabled by default
  • Schema branching requires CLI workflow (more friction than Neon's API/dashboard approach)

Turso

Type: SQLite at the edge (libSQL) GitHub stars: 13K+ (libSQL repo) Creator: ChiselStrike / Turso team Technology: libSQL (open-source fork of SQLite)

Turso takes SQLite — the most deployed database engine in the world — and makes it available as a distributed, edge-replicated database service. The underlying technology is libSQL, a Turso-maintained fork of SQLite that adds replication.

Connection

import { createClient } from '@libsql/client';

const client = createClient({
  url: process.env.TURSO_DATABASE_URL!,
  authToken: process.env.TURSO_AUTH_TOKEN,
});

const result = await client.execute('SELECT * FROM users WHERE active = 1');
console.log(result.rows);

With Drizzle ORM

import { drizzle } from 'drizzle-orm/libsql';
import { createClient } from '@libsql/client';
import { users } from './schema';

const client = createClient({
  url: process.env.TURSO_DATABASE_URL!,
  authToken: process.env.TURSO_AUTH_TOKEN,
});

const db = drizzle(client);
const activeUsers = await db
  .select()
  .from(users)
  .where(eq(users.active, true));

Edge Replication

Turso's primary advantage: SQLite databases replicated to edge locations globally.

// Turso creates read replicas in 35+ regions
// Your primary write database is in one region
// Read replicas are in every region you choose

// From a Cloudflare Worker in Singapore:
// Read query → Singapore edge replica (~2ms)
// Write query → Primary in us-east-1 (~180ms)

// vs. centralized database:
// Read query → us-east-1 from Singapore (~180ms)
// Write query → us-east-1 from Singapore (~180ms)

For read-heavy applications with global users, this latency reduction (90% on reads) is significant.

Multi-Tenant Databases

Turso supports up to 500 databases on the free tier, making it ideal for multi-tenant architectures where each tenant gets their own isolated database:

// Create a database per tenant
import { createClient as createTursoClient } from '@libsql/turso';

const turso = createTursoClient({ token: process.env.TURSO_API_TOKEN });

// Create a database for a new tenant
const db = await turso.databases.create({
  name: `tenant-${tenantId}`,
  location: 'iad', // Primary location
});

// Connect to the tenant's database
const client = createClient({
  url: db.hostname,
  authToken: await turso.databases.createToken(db.name),
});

Turso Pricing (2026)

PlanPriceDatabasesStorageEdge Replicas
Free$05009 GB3 locations
Developer$4.99/monthUnlimited24 GBUnlimited
Scaler$29/monthUnlimited108 GBUnlimited

Turso Limitations

  • SQLite only (no PostgreSQL, MySQL)
  • Write-heavy workloads don't benefit (writes go to primary region)
  • SQLite limitations: no full-text search without extensions, different than Postgres behavior
  • Smaller ecosystem than Postgres (fewer extensions, tools, expertise)

Latency Comparison

ScenarioNeonPlanetScaleTurso
Cold start~300ms~50ms~5ms
Local read (same region)~5ms~5ms~2ms
Remote read (cross-region)~150-200ms~150-200ms~5-20ms (edge)
Write (any scenario)~10ms~10ms~15ms (to primary)

Turso's edge replication only helps reads — and only when edge replicas are deployed near users.

Choosing the Right Database

Choose Neon if:

  • You want PostgreSQL with a free tier
  • Schema branching for PR environments fits your workflow
  • You're building on any standard stack (Next.js, Remix, Express)
  • Your team knows Postgres and prefers to stay in that ecosystem
  • Scale-to-zero cost savings matter for low-traffic applications

Choose PlanetScale if:

  • You need MySQL compatibility (migrating existing MySQL apps)
  • Production reliability and uptime guarantees are non-negotiable
  • Non-blocking schema changes are important for zero-downtime deployments
  • You're running high-traffic SaaS that needs Vitess horizontal scaling

Choose Turso if:

  • Edge deployment (Cloudflare Workers, Deno Deploy, Fastly) is your target
  • Read-heavy global workloads where latency matters
  • Multi-tenant architecture where each tenant gets an isolated SQLite database
  • SQLite is acceptable (scripts, embedded data, simpler schemas)

The 2026 Default

For most new TypeScript projects: Neon. The free tier is generous, Postgres is the most supported database in the TypeScript ecosystem (Drizzle, Prisma, Kysely all prioritize Postgres), and the schema branching feature is legitimately useful for teams managing migrations across environments.

Turso is the right call when you're building on edge runtimes or need the multi-tenant database-per-tenant pattern. PlanetScale is the right call when production reliability beats all other concerns and your team has MySQL expertise.

Compare database clients and ORMs on PkgPulse.

Comments

Stay Updated

Get the latest package insights, npm trends, and tooling tips delivered to your inbox.