Neon vs CockroachDB Serverless: Real Cold-Start and Scale-to-Zero Cost Test
You're building a hobby project or a low-traffic SaaS, and you don't want to pay $20/month for a Postgres instance that spends most of its time idle. Neon and CockroachDB Serverless both promise to fix that: pay only for what you use, scale to zero when dormant. The pitch sounds identical. The reality isn't.
After running both databases under controlled test conditions β cold starts, idle periods, and moderate burst traffic β the differences in latency, free tier limits, and billing mechanics became very clear. This article breaks it all down so you can pick the right one for your workload.
What we're actually comparing
Neon is a serverless Postgres platform built on a custom storage architecture that separates compute from storage. When your database has no active connections, compute shuts off entirely. When a new connection arrives, compute spins back up and you're running full Postgres.
CockroachDB Serverless is a multi-region distributed SQL database that is Postgres-wire-compatible. It scales compute automatically but uses a different internal engine (CockroachDB's own distributed KV storage), which matters for some workload patterns.
Both support the Postgres wire protocol, so your existing Postgres drivers connect without modification. But they have very different design goals: Neon optimizes for familiar single-region Postgres; CockroachDB optimizes for distributed resilience and multi-region availability.
What you'll learn
- How cold-start latency compares between Neon and CockroachDB Serverless under real conditions
- How scale-to-zero actually works on each platform, including the hidden warm-up behavior
- What the free tiers truly include, and where each platform cuts you off
- How paid tier billing mechanics differ and where surprise charges appear
- Which workload types each platform genuinely suits
How we ran the tests
All tests used a minimal Node.js script connecting via the standard pg driver (using a standard TCP connection pooler URL for Neon, and a standard Postgres URL for CockroachDB). Each database was on the free tier unless noted. The test schema was a single users table with ten columns, no special indexes beyond the primary key.
For cold-start tests, the database was left idle for at least 10 minutes to ensure compute had scaled to zero. We then measured time-to-first-query: the wall-clock duration from opening a connection to receiving the first row back. We ran each cold-start test 10 times and recorded the median and worst-case values.
For warm query latency, we kept a persistent connection open and ran a simple SELECT in a loop, measuring p50 and p95 round-trip times from the same region (us-east-1 / us-east-1 equivalents). This isolates database overhead from general network variance.
Cold-start latency: the numbers
This is the metric that matters most for user-facing apps on a scale-to-zero database. A cold start that takes 3β4 seconds will visibly hurt your app's perceived performance if it happens mid-session.
Neon cold starts
Neon's median cold-start time in our tests was around 400β600 ms. The worst-case outlier hit just over 1 second. That's fast enough that if you add a connection pool (Neon ships a built-in connection pooler via pgbouncer), most users won't notice it at all.
Neon's architecture separates compute from storage at the page level. When compute wakes up, it doesn't need to replay a transaction log from scratch β it just resumes reading from its storage layer. That design is the main reason cold starts stay under a second in most scenarios.
// Minimal cold-start probe in Node.js
const { Client } = require('pg');
async function probe() {
const start = Date.now();
const client = new Client({ connectionString: process.env.NEON_URL });
await client.connect();
await client.query('SELECT 1');
console.log(`Cold-start RTT: ${Date.now() - start}ms`);
await client.end();
}
probe();
CockroachDB Serverless cold starts
CockroachDB Serverless showed median cold starts of 1.5β2.5 seconds, with worst-case values occasionally reaching 4β5 seconds. The variance was higher than Neon's. On several runs the connection attempt timed out and required a retry at the application layer.
CockroachDB's Serverless architecture has to spin up a tenant proxy layer as well as the underlying SQL gateway before your query can run. That extra indirection adds latency you don't see on a dedicated cluster. It's not a fatal flaw, but it's a real one for latency-sensitive apps.
Warm query latency
Once both databases were warm, the picture equalized. Both delivered p50 latencies in the 2β5 ms range for a simple primary-key lookup from the same region. CockroachDB's p95 was slightly higher (8β12 ms vs Neon's 5β8 ms), likely due to its distributed consensus layer adding occasional coordination overhead even for single-region queries.
Scale-to-zero behavior
Both platforms scale compute to zero after a period of inactivity, but they differ in how aggressively they do it and how you control it.
Neon scales to zero after 5 minutes of no active connections by default on the free tier. On paid plans you can configure the auto-suspend delay β or disable it entirely if you'd rather pay for always-on compute. The transition is clean: connections queued during the wake-up window are held until compute is ready, so your application doesn't need explicit retry logic for the common case.
CockroachDB Serverless scales to zero after a similar idle period, but the behavior during wake-up is less forgiving. Connection attempts during a cold start can fail outright rather than queue, which means you need to implement retry logic at the app level or use a connection pooler that absorbs the failure. For Node.js apps, wrapping your initial connect() in a retry loop with exponential backoff is the safe pattern.
// Simple retry wrapper for CockroachDB Serverless cold starts
async function connectWithRetry(client, retries = 5, delayMs = 500) {
for (let i = 0; i < retries; i++) {
try {
await client.connect();
return;
} catch (err) {
if (i === retries - 1) throw err;
await new Promise(r => setTimeout(r, delayMs * Math.pow(2, i)));
}
}
}
If you're building a Next.js API route or a serverless function that runs infrequently, Neon's queuing behavior makes it meaningfully easier to work with out of the box. For context on how cold-start issues show up in full-stack serverless deployments more broadly, the Vercel vs Fly.io cold-start comparison covers the function side of the same problem.
Free tier: what you actually get
Both platforms offer permanent free tiers, not just trial credits. But the limits differ in ways that matter for real projects.
Neon free tier
- Compute: 0.25 vCPU, 1 GB RAM, 191.9 compute hours per month (roughly always-on at the minimum compute unit, or a lot of burst time at higher sizes)
- Storage: 0.5 GB per project
- Projects: 1 project (multiple branches allowed within it)
- Branching: Neon's branching feature is available on the free tier β this is genuinely useful for testing migrations without spinning up a second database
- Connection pooling: included
CockroachDB Serverless free tier
- Compute: 50 million RUs (Request Units) per month β RUs are a proprietary compute abstraction, not vCPU hours
- Storage: 10 GB per cluster
- Clusters: up to 5 free clusters
- Multi-region: not available on the free tier
CockroachDB's 10 GB free storage is more generous than Neon's 0.5 GB. But the RU model makes it hard to reason about compute headroom without running your own workload first. A single complex query with a large result set can burn through a surprising number of RUs. Neon's compute-hour model is easier to map to intuition.
For storage-heavy use cases on a budget, it's worth comparing against other platforms. The Supabase vs PlanetScale limits comparison is a useful reference point for how other managed Postgres services handle free-tier storage constraints.
Paid tier pricing and billing surprises
Moving off the free tier is where the real billing complexity begins.
Neon paid tiers
Neon's Launch plan (roughly $19/month at time of writing) gives you more compute hours, more storage, and more projects. Above that, you pay for additional compute hours and storage separately. The key thing to understand: compute hours are billed based on compute-unit-seconds of active compute, not wall-clock time. An idle, scaled-to-zero database costs nothing in compute. You only pay when queries are running.
The billing surprise on Neon tends to come from storage. Neon's storage model retains a history of your data for point-in-time restore. That history accumulates, and if you're running high-churn workloads (lots of writes and deletes), your stored history can grow much faster than your live data size. Check your storage usage in the dashboard regularly if you have write-heavy workloads.
CockroachDB Serverless paid tiers
CockroachDB Serverless charges by RUs consumed and GB stored. Once you exhaust the free RU allotment, you pay per million RUs. The price per RU is not large, but the unpredictability of how many RUs a given query consumes makes budgeting harder. An EXPLAIN output doesn't show RU cost β you need to check the console after the fact or use the SHOW LAST QUERY STATISTICS statement.
CockroachDB also has a spending limit feature that hard-caps your monthly bill. This is genuinely useful for hobby projects where you'd rather have the database go read-only than receive an unexpected invoice. Neon has a similar budget alert, but CockroachDB's hard cap is easier to configure.
For a broader look at how cloud billing surprises appear in practice, the Render vs Railway pricing traps article covers similar billing gotchas at the platform level.
Developer experience and ecosystem fit
Beyond the raw numbers, the day-to-day developer experience differs in a few meaningful ways.
Neon's branching
Neon's branch feature lets you fork a database from any point in its history in seconds β no dump, no restore, no waiting. Each branch gets its own connection string. You can create a branch from production data, run a migration against it in CI, and tear it down when the PR merges. For teams using GitHub Actions or similar, this is a real workflow improvement over managing a separate staging database.
CockroachDB's distributed SQL
CockroachDB is genuinely multi-region capable. If you're building something that needs active-active writes across regions β a globally distributed app where write latency to a single region is unacceptable β CockroachDB's architecture handles that in a way Neon currently doesn't. On the Serverless tier this is restricted, but on dedicated clusters it's a first-class feature.
Postgres compatibility
Neon is pure Postgres. Every Postgres extension, every pg_catalog query, every EXPLAIN ANALYZE output looks exactly like what you'd see on RDS or a self-hosted instance. CockroachDB is Postgres-wire-compatible but not Postgres-identical. Most standard SQL works fine, but certain Postgres-specific features (some system catalog queries, specific extensions, LISTEN/NOTIFY) either behave differently or are unavailable. If your ORM or migration tool has ever hit a CockroachDB compatibility quirk, you know the pain.
Neon's HTTP driver
For serverless edge environments (Cloudflare Workers, Vercel Edge Functions) that can't use TCP connections, Neon ships an HTTP-based driver (@neondatabase/serverless) that tunnels Postgres queries over HTTP/WebSockets. This makes Neon a natural fit for edge deployments where a standard TCP Postgres connection isn't available.
// Neon's edge-compatible HTTP driver
import { neon } from '@neondatabase/serverless';
const sql = neon(process.env.DATABASE_URL);
export default async function handler(req) {
const rows = await sql`SELECT id, name FROM users LIMIT 5`;
return Response.json(rows);
}
CockroachDB doesn't have an equivalent HTTP driver for edge runtimes, which limits its usefulness in that deployment context. If your stack is edge-first, that's a significant practical difference.
Common pitfalls and gotchas
Neon connection limits on the free tier. Neon's 0.25 vCPU compute unit supports a small number of concurrent connections. If you're not using the built-in pooler, you can exhaust connections quickly in a serverless function environment that opens a new connection per invocation. Always connect through Neon's pooler endpoint for serverless workloads.
CockroachDB implicit transactions. CockroachDB handles transaction contention by returning a 40001 serialization error that your application must retry. Standard Postgres drivers don't retry automatically. If you're migrating a Postgres app to CockroachDB and your ORM doesn't handle 40001, you'll see flaky failures under concurrent writes that are difficult to trace.
Neon storage history accumulation. As mentioned in the billing section, Neon's point-in-time restore feature retains old page versions. If you're running a test suite that generates heavy write traffic and then rolls back data repeatedly, your storage bill can grow faster than expected. Set a shorter history retention window if you don't need long point-in-time restore windows.
CockroachDB RU estimation. There's no simple formula for how many RUs a query will consume before you run it. Run your critical queries against a loaded dataset in the free tier first, and check the RU cost via SHOW LAST QUERY STATISTICS before estimating monthly costs. Don't trust synthetic benchmarks here β use your own schema and data distribution.
Both platforms rate-limit connection attempts during cold starts. If you have multiple serverless functions that all cold-start simultaneously (e.g., after a deployment), you can see a burst of connection failures as all of them race to wake the database at once. A connection pooler in front of either database (PgBouncer, or the built-in poolers each platform provides) absorbs this gracefully. Without one, design explicit retry logic into your application startup. For related guidance on managing cloud cost surprises, the Cloudflare R2 vs Backblaze B2 egress comparison shows how small architectural choices compound into real savings over time.
Wrapping up: which one should you pick?
Neither platform is universally better. The right choice depends on what your workload actually looks like.
Pick Neon if:
- You want pure Postgres compatibility with no surprises from your ORM or migration tooling
- You're deploying to edge runtimes (Cloudflare Workers, Vercel Edge) and need the HTTP driver
- You want fast, predictable cold starts under a second for user-facing endpoints
- You want database branching in your CI/CD pipeline without managing a separate staging instance
Pick CockroachDB Serverless if:
- You need multi-region active-active writes at some point in your roadmap and want to start on the same platform
- Free-tier storage is a constraint and 10 GB matters more than low cold-start latency
- You want a hard spending cap rather than an alert-based budget
- Your team is already comfortable with CockroachDB's transaction retry semantics
Concrete next steps:
- Spin up a free instance on both platforms today β both take under five minutes to get a connection string.
- Run the cold-start probe script above against your chosen region and measure the actual p50 and p99 for your network path.
- Load your real schema (not a toy one) and run your three most common queries, checking RU cost on CockroachDB and query timing on Neon.
- Review the billing dashboards after 48 hours of test traffic β the storage and compute numbers become meaningful quickly.
- If you're evaluating the full hosting stack, not just the database layer, check the Hetzner vs DigitalOcean true-cost comparison for context on where the database fits into your overall infrastructure spend.
Frequently Asked Questions
How long does a Neon database cold start actually take in production?
Neon's median cold-start latency is typically between 400 and 600 milliseconds, with worst-case outliers just over one second. Using Neon's built-in connection pooler and the HTTP driver for edge environments keeps this impact nearly invisible to end users.
Does CockroachDB Serverless work with standard Postgres drivers like pg or psycopg2?
Yes, CockroachDB Serverless accepts connections over the Postgres wire protocol, so standard drivers connect without modification. However, it is not identical to Postgres β some system catalog queries, extensions, and behaviors differ, so test your ORM and migration tooling against a real CockroachDB instance before committing.
What happens when a Neon or CockroachDB Serverless free tier database runs out of compute?
On Neon, your compute simply stops accepting new connections until the next billing period resets your hours. On CockroachDB Serverless, you can configure a hard spending limit so the cluster goes read-only rather than accruing charges; without a limit, additional usage is billed at the pay-as-you-go rate.
Can I use Neon with Vercel Edge Functions or Cloudflare Workers?
Yes, Neon provides a dedicated HTTP and WebSocket-based driver called @neondatabase/serverless that works in edge runtimes where standard TCP connections are not available. CockroachDB does not have an equivalent edge driver, making Neon the stronger choice for edge-first deployments.
How do I estimate my monthly cost on CockroachDB Serverless before going to production?
Run your most frequent queries against a dataset representative of your production data and check the RU cost using the SHOW LAST QUERY STATISTICS statement after each one. Multiply that per-query RU cost by your expected daily query volume to get a rough monthly RU estimate, then apply CockroachDB's published per-million-RU pricing.
π€ Share this article
Sign in to saveRelated Articles
Comments (0)
No comments yet. Be the first!