CapyDB/ docs
Reference

Benchmarks

Measured latency and throughput numbers - what one query costs, what a connection costs, and what a noisy neighbor actually does - with full methodology and a reproducible harness.

How we measure (and how to read this page)

All numbers below come from capybench, our open-source managed-Postgres benchmark harness, run against production CapyDB infrastructure - the same nodes that serve real customer cells, not an idle lab box. The load client is colocated in the same region as the database (0.6 ms network round-trip). That matters: latency measured across the public internet measures your ISP, not the database. Expect your numbers to be these numbers plus your app-to-region round-trip.

Test cells are standard business-plan projects created through the public API, connected through the same TLS proxy every customer uses, with full certificate verification on. Nothing is special-cased.

Latest campaign: 2026-08-17, Postgres 17.10, Helsinki region.

What one query costs

Measured with 500 repeats per variant on a warm connection (driver auto-prepare disabled, so the numbers hold on both ports), plus 30 full fresh connects:

VariantDirect (5432)Pooled (6432)
SELECT 1, warm connection - p50 / p950.57 / 0.67 ms0.66 / 0.77 ms
Indexed point-select, warm connection - p50 / p950.70 / 0.81 ms0.83 / 1.04 ms
Fresh connection (TCP + TLS + SCRAM) + first query - p50 / p9525.7 / 46.3 ms15.3 / 18.5 ms

Two things worth internalizing:

  • A query on a warm connection has a sub-millisecond p95. There is no HTTP gateway, no REST translation layer, and no per-request auth handshake between your app and Postgres - the wire protocol is the API.
  • The pooled port connects faster than the direct port (the pooler already holds authenticated server connections) and costs ~0.2 ms extra per query. If your platform opens connections per request - serverless, edge workers - the pooled URL is the right default, exactly as the pooling guide says.

Full-transaction latency and throughput

pgbench read-write transactions (TPC-B-style, roughly seven statements each, writes included) on the direct port. Percentiles are exact, computed from per-transaction logs:

Concurrent clientsTransactions/secp50p95p99
11387.1 ms9.5 ms11.7 ms
89157.9 ms13.6 ms17.6 ms
161 7008.2 ms14.9 ms21.1 ms
322 30111.9 ms25.8 ms38.7 ms

Through the pooled port the same sweep gives up 10-20 % of throughput and, at high concurrency, actually posts a lower p95 (24.2 ms at 32 clients) - transaction pooling queues excess work instead of letting it pile onto the server, which caps peak throughput and smooths the tail. That is the trade it exists to make.

Scale-to-zero wake

Twelve forced sleep→wake cycles, timing a cold connect + SELECT 1 (the first connection is what wakes a paused cell):

  • p50 ≈ 308 ms, worst observed 358 ms.

A paused cell answers its first query in about a third of a second. Budget one extra round-trip-ish pause on the first request after idleness, not a multi-second cold boot; connections after that first one are at steady-state latency immediately.

Preview database creation

Creating a preview (copy-on-write branch) of a parent cell, timed from API call to the branch answering SELECT 1:

Parent sizeTime (avg of 3)
256 MB10.2 s
1 GB15.6 s

Four times the data costs about 50 % more time - creation is dominated by orchestration and starting the new Postgres, not by copying your data. Multi-gigabyte parents do not turn preview creation into a coffee break.

Previews wake up warm

Because a preview is a copy-on-write branch, it shares its storage blocks with the parent - and the node's cache works at the block level, so a fresh preview inherits the parent's hot cache instead of starting cold. Measured on a ~500 MB parent whose data was in active use: the preview's first-ever full-table scan ran in 255 ms, the same as a warm scan on the parent itself and about 2.6× faster than a fully cold read of the same data. Your CI run against a just-created preview starts at production cache temperature.

Noisy neighbors: what we claim and what we measured

Standard cells share nodes. We publish this number precisely because most providers do not: with an aggressor cell on the same node sustaining ~1 640 transactions/sec for the whole measurement window, a victim cell kept 49 % of its solo throughput and its p99 moved from 28 ms to 72 ms (×2.55).

That is proportional fair-share, not isolation. Equal-plan cells under contention each keep roughly their share of the node; a neighbor's burst cannot starve you out, and the per-cell CPU clamp means no single tenant can take the whole node. If your workload cannot tolerate any neighbor effect, that is what dedicated placement is for - talk to us.

We consider an honestly-measured ×2.55 more useful to you than an unmeasured "fully isolated".

Reproducing

git clone https://github.com/capy-base/capybench && cd capybench
uv sync && sudo apt-get install sysbench postgresql-client
# provision two projects, put their URLs in capybench.toml, then - from a client
# colocated with your region:
uv run capybench run --config capybench.toml
uv run capybench report --config capybench.toml --out report.html

The harness records every sample with the client's region and machine info, refuses to hide a dead load generator (the noisy-neighbor scenario hard-fails if the aggressor was not actually sustaining load), and produces a self-contained HTML report. Community runs - including against other providers - are welcome.