Numbers are per-process throughput — SQLite is single-writer, so vertical scaling of writes is bounded. Reads scale across a connection pool.
The values in the tables below were measured on earlier reference hardware (a 2024 Apple M-series laptop, 16 GB RAM) and are pending re-measurement on the current reference machine (2025 Mac Studio M3 Ultra, 96 GB). Expect the M3 Ultra to land meaningfully higher — treat these as a lower bound until refreshed.
Re-run with:
cargo bench -p pylon-runtime --bench bench
cargo bench -p pylon-runtime --bench realtime_bench
Data plane (single-writer SQLite)
| Operation | Ops/sec | Per op |
|---|
insert (User, 3 fields) | 68,000 | 14.6µs |
insert (Todo, 4 fields) | 77,000 | 13.0µs |
update | 89,000 | 11.2µs |
delete + reinsert | 40,000 | 24.7µs |
get_by_id | 519,000 | 1.9µs |
lookup by unique field | 484,000 | 2.1µs |
query_filtered (equality) | 24,000 | 40.8µs |
query_filtered ($like) | 10,000 | 96.9µs |
list (1000 rows) | 2,700 | 363µs |
query_graph (no filter, 1000 rows) | 1,500 | 660µs |
Realtime path
| Operation | Ops/sec | Per op |
|---|
change_log.append | 5M | 198ns |
change_log.pull(100) | 85,000 | 11.7µs |
ws_hub.broadcast (enqueue) | 30,000 | 32.5µs |
The WS hub broadcast number is enqueue-side: it fans out to 16 shard worker threads that each push to connected clients. Real delivery rate depends on client count, message size, and TCP send buffers.
What these numbers mean for deploy sizing
Small (1 vCPU, 1 GB RAM, ~$5/mo VPS)
- Up to ~20k writes/minute sustained, or bursts to 30k/minute
- Up to ~10k concurrent WS connections (64 KB stack per reader thread)
- Good for a few thousand active users at webapp levels of chattiness
Medium (2 vCPU, 4 GB RAM, ~$25/mo VPS)
- Up to ~50k writes/minute sustained
- Up to ~40k concurrent WS connections
- Good for 50k active users; room for complex queries without eviction
Large (4+ vCPU, 8+ GB RAM)
- Write ceiling is still single-writer SQLite (~70k inserts/sec peak). If you’re pinned on writes, move to Postgres (
postgres-live feature) or shard the app across databases.
- Reads scale with the read-connection pool. 4 pool connections × 500k reads/sec = 2M reads/sec ceiling.
When to switch backends
You’re on SQLite and need Postgres when
- Sustained write rate > 50k/sec (you’re at SQLite’s single-writer limit)
- Multiple processes need to write (replicas, HA failover)
- You need online DDL / zero-downtime migrations at scale
- Storage > 100 GB (not a hard limit, but WAL checkpoints get painful)
You can stay on SQLite when
- Single-process deployment
- Full DB fits comfortably in RAM for the read pool
- You back up with
pylon backup on a schedule
On Pylon Cloud
Cloud autoscales the HTTP, WebSocket, and shard tiers separately. You don’t pre-provision — you pay for what you use. The numbers above are useful for self-hosted capacity planning; on Cloud you don’t think about them.
For multiplayer apps with sticky shard connections, latency to your players matters — set the workspace region accordingly when signing up.
What’s NOT measured here
- Multi-client read contention (connection-pool fair-share)
- TLS handshake cost (reverse proxy terminates TLS)
- Network RTT — production numbers will be bounded by network first
- Shard tick budget for realtime game state — depends on
SimState::tick
For a real capacity estimate under your workload, run pylon bench against a representative fixture and the manifest you’ll ship with.