Cloud Database & Compute Shootout
Eleven free plans. One recorded US-East run. Pick plans, then read the chart.
Free plans
Select a plan. The long note stays closed until you do.
| Plan | Storage | Compute | Dormancy | Hidden cost |
|---|---|---|---|---|
| Pixeltable Cloud | 50 GB media storage, 10 GB database storage | Hosted compute included | No forced sleep or auto-pause; always-warm schema & endpoints | Zero. ffmpeg, Whisper, CLIP & vector indexing run in-schema; no external orchestrators or vector DBs needed. |
| Railway | Shared container disk / persistent volume | $5 monthly credit (approx. 500 execution hours total) | Sleeps or shuts down when $5 credit exhausts; 24/7 Postgres burns out in ~20 days | Railway as Postgres: template runs raw PostgreSQL 16 container that drains the $5 credit 24/7. Zero built-in multimodal, vector indexing, or pipeline triggers. |
| Render | Ephemeral container filesystem | 750 free instance hours/month (512 MB RAM) | Spins down after 15 minutes of inactivity (50s cold start); Free Postgres deleted after 30 days | Render as Postgres: free tier PostgreSQL databases expire and are permanently wiped after 30 days! Free web services suffer 50s cold starts after 15m idle. |
| Cloudflare | 5 GB D1 SQLite, 10 GB R2 object storage | 100,000 Workers requests/day, 5M D1 reads/day, 5M Vectorize queries/mo | Always warm across 300+ global edge locations; 0ms cold starts | Cloudflare D1 & Vectorize: Workers free plan has a hard 10ms CPU time limit. V8 isolates cannot run Python ML libraries (PyAV, Whisper, PyTorch). Must hop to Workers AI or external GPU clusters. |
| Modal | Ephemeral container disk + volume storage | $30/month recurring compute credit | Containers shut down when idle (zero cost while inactive; 1-2s container cold boot) | Stateless: must maintain an external database and object store to persist state and query embeddings. |
| Neon | 1 GB storage per project | 100 compute unit (CU) hours/mo | Compute scales to zero after 5 minutes of idle (1-3s wake-up cold start) | Requires external queue workers, object storage, and custom migration scripts for AI model updates. |
| Supabase | 500 MB database, 1 GB file storage | Shared compute, 500k Edge Function invocations/mo | Projects automatically paused after 7 days of inactivity | External compute service required for heavy media transforms (Deno runtime cannot run ffmpeg/Whisper); manual vector backfill scripts. |
| Turso | 5 GB total storage | 500M row reads/mo, 10M row writes/mo | No inactivity pause; always available | Requires external file storage for media and custom Python workers to encode vectors before insertion. |
| Prisma Postgres | 500 MB storage | Shared compute pool | No forced sleep during public beta | Requires external worker processes for media processing and model inference; manual backfill scripts. |
| Convex | 1 GB file & document storage | 1 Million function calls/mo | No dormancy pause on active free accounts | Requires external HTTP compute service to run ffmpeg or local ML models; action/mutation hopping. |
| Vercel | Edge KV / Blob / Postgres (via partner integrations) | 100,000 serverless function executions/mo, 100 GB-hours | Scale-to-zero serverless lambdas; cold starts on idle wake | Stateless frontend platform: requires external database and background task workers for long-running ETL. |
Warm latency
Lower is better. Bar length is the p50. A Worker reply and a SQL round trip are different operations.
| Rank | Plan | Result | What was timed |
|---|---|---|---|
| 1 | Cloudflare Workers | 11.6 ms | compute. Min 10.7 ms. p95 14.1 ms. 200 OK. |
| 2 | Railway Postgres | 22.1 ms | database. Min 21.6 ms. p95 44.0 ms. 200 OK. |
| 3 | Railway | 25.9 ms | compute. Min 24.4 ms. p95 29.0 ms. 200 OK. |
| 4 | Render | 27.0 ms | compute. Min 22.5 ms. p95 30.7 ms. 200 OK. |
| 5 | Render Postgres | 66.1 ms | database. Min 64.6 ms. p95 131.6 ms. 200 OK. |
| 6 | Neon Serverless PG | 68.3 ms | database. Min 66.9 ms. p95 73.3 ms. 200 OK. |
| 7 | Turso libSQL | 90.7 ms | database. Min 83.4 ms. p95 118.9 ms. 200 OK. |
| 8 | Vercel | 94.9 ms | compute. Min 90.9 ms. p95 115.0 ms. 200 OK. |
| 9 | Prisma Postgres | 98.6 ms | database. Min 97.4 ms. p95 198.0 ms. 200 OK. |
| 10 | Convex | 99.4 ms | database. Min 82.5 ms. p95 125.4 ms. 200 OK. |
| 11 | Pixeltable Compute | 104.4 ms | compute. Min 102.8 ms. p95 105.1 ms. 200 OK. |
| 12 | Supabase PostgREST | 116.2 ms | database. Min 83.9 ms. p95 167.2 ms. 201 Created. |
| 13 | Pixeltable Ingest | 128.3 ms | database. Min 124.9 ms. p95 143.8 ms. 200 OK. |
| 14 | Modal | 271.3 ms | compute. Min 266.0 ms. p95 295.2 ms. 200 OK. |
Stateless compute
Higher is better. Bar length is the burst rate.
| Rank | Plan | Result | What was timed |
|---|---|---|---|
| 1 | Railway | 435.2 req/s | FastAPI in Debian container. Warm p50 25.9 ms. ~2s (if configured to sleep; always-on consumes credits) 0.5 - 1.0 vCPU shared $5 trial credit / mo (~500 execution hours) |
| 2 | Cloudflare Workers | 395.5 req/s | JavaScript / Wasm isolate. Warm p50 11.6 ms. < 5ms worldwide (zero container overhead) 10ms CPU time per invocation (Standard Free plan ceiling) 100,000 requests/day |
| 3 | Vercel | 238.7 req/s | FastAPI / Python 3.11 serverless. Warm p50 94.9 ms. 200ms - 800ms on lambda scale-up 10s maximum execution duration (Hobby plan) 100,000 invocations/month |
| 4 | Render | 128.4 req/s | FastAPI in container (512 MB). Warm p50 27.0 ms. ~50 seconds after 15m idle sleep 0.5 vCPU shared 750 instance hours/month |
| 5 | Pixeltable Compute | 56.1 req/s | Pixeltable Execution Engine + FastAPI. Warm p50 104.4 ms. None (always-warm managed endpoint) Shared community cluster compute 50 GB media + 10 GB database storage |
| 6 | Modal | 27.3 req/s | FastAPI ASGI mounted inside Modal Container. Warm p50 271.3 ms. 1.2s - 2.5s container initialization Customizable up to 64 vCPU & H100 GPUs $30/month recurring compute credit |
Not timed: Neon, Supabase, Turso, Prisma Postgres, Convex
Point reads
Lower is better. Bar length is the p50.
| Rank | Plan | Result | What was timed |
|---|---|---|---|
| 1 | Cloudflare Workers | 11.6 ms | Edge V8 Isolate response |
| 2 | Railway Postgres | 22.1 ms | Direct SELECT via TCP proxy |
| 3 | Turso libSQL | 65.4 ms | SELECT 10 rows (HTTP pipeline) |
| 4 | Neon Serverless PG | 65.7 ms | SELECT 10 rows (SQL proxy) |
| 5 | Render Postgres | 66.1 ms | Direct SELECT via Virginia SSL |
| 6 | Prisma Postgres | 90.9 ms | SELECT 10 rows (asyncpg pool) |
| 7 | Convex | 99.4 ms | db.query("docs").take(10) |
| 8 | Supabase PostgREST | 111.4 ms | GET ?select=*&limit=10 |
| 9 | Pixeltable Query | 112.5 ms | Table select & filter query |
| 10 | Modal | 186.4 ms | FastAPI ASGI GET /read |
Not timed: Vercel
Single-row writes
Lower is better. Bar length is the p50.
| Rank | Plan | Result | What was timed |
|---|---|---|---|
| 1 | Railway Postgres | 67.0 ms | Direct SQL INSERT over TCP proxy PostgreSQL WAL commit |
| 2 | Neon Serverless PG | 68.3 ms | Direct SQL INSERT over WebSocket/HTTP pooler ACID WAL flush to cloud storage architecture |
| 3 | Pixeltable Ingest (Async Job) | 68.5 ms | Immediate HTTP ACK with Job ID + background DAG worker execution (background=True) ACID PostgreSQL record + immutable version snapshot |
| 4 | Turso libSQL | 90.7 ms | HTTP pipeline POST execute with remote WAL sync SQLite WAL committed to primary writer |
| 5 | Prisma Postgres | 98.6 ms | Single SQL INSERT over asyncpg connection pool PostgreSQL WAL commit via edge pooler |
| 6 | Convex | 99.4 ms | Reactive mutation handler commit to document table Deterministic STM (software transactional memory) |
| 7 | Supabase PostgREST | 116.2 ms | PostgREST HTTP POST with JSON body into Postgres 17 PostgreSQL synchronous commit WAL |
| 8 | Pixeltable Ingest | 128.3 ms | Versioned table row insert + automatic computed column DAG trigger ACID PostgreSQL record + immutable version snapshot |
| 9 | Render Postgres | 198.3 ms | Direct SQL INSERT over Virginia SSL PostgreSQL WAL commit |
Not timed: Cloudflare, Modal, Vercel
Batch ingest
100 rows, one payload. Higher is better. Bar length is rows per second. Payloads are not one schema.
| Rank | Plan | Result | What was timed |
|---|---|---|---|
| 1 | Neon Serverless PG | 1,316 rows/s | Single multi-row SQL INSERT query via pooler 0.076 s. |
| 2 | Railway Postgres | 1,107 rows/s | Multi-row SQL INSERT (100 rows) via TCP proxy 0.090 s. |
| 3 | Supabase PostgREST | 817 rows/s | Single JSON array POST to PostgREST endpoint 0.122 s. |
| 4 | Render Postgres | 603 rows/s | Multi-row SQL INSERT (100 rows) via Virginia SSL 0.166 s. |
| 5 | Pixeltable Python SDK | 568 rows/s | Client SDK insert() batch with schema validation 0.176 s. |
| 6 | Prisma Postgres | 503 rows/s | Single multi-row SQL INSERT over pooled connection 0.199 s. |
| 7 | Turso libSQL | 33 rows/s | Pipeline batch with 100 execute statements in 1 payload 3.052 s. |
Not timed: Cloudflare, Modal, Convex, Vercel
Burst
50 workers, 100 requests. Higher is better. Bar length is requests per second.
| Rank | Plan | Result | What was timed |
|---|---|---|---|
| 1 | Railway | 435 req/s | compute. p50 88 ms. p95 197 ms. 100%. Pure lightweight container pass-through; zero database persistence |
| 2 | Cloudflare Workers | 396 req/s | compute. p50 66 ms. p95 239 ms. 100%. Global Edge V8 isolates; fastest burst p50 (66ms) with 0ms cold starts |
| 3 | Railway Postgres | 375 req/s | database. p50 122 ms. p95 150 ms. 100%. Direct pooled SQL connections over public TCP proxy (c=50, about 100 requests) |
| 4 | Vercel | 239 req/s | compute. p50 161 ms. p95 303 ms. 100%. Serverless Edge scaling; parallel lambda function invocations |
| 5 | Neon Serverless PG | 199 req/s | database. p50 186 ms. p95 428 ms. 100%. Fastest database write burst; direct SQL execution over pooler |
| 6 | Supabase PostgREST | 175 req/s | database. p50 218 ms. p95 411 ms. 100%. PostgREST HTTP proxy directly writing into hosted PostgreSQL |
| 7 | Convex | 137 req/s | database. p50 225 ms. p95 463 ms. 100%. Managed reactive backend mutation; 136 req/s transactional burst |
| 8 | Render | 128 req/s | compute. p50 298 ms. p95 559 ms. 100%. Free instance handled 50 concurrent requests without thread starvation |
| 9 | Pixeltable Ingest (Async Job) | 97 req/s | database. p50 395 ms. p95 623 ms. 100%. background=True delivers immediate ACK with job_url, achieving 96.6 req/s burst throughput and 0% errors while executing full DAG in background workers |
| 10 | Render Postgres | 71 req/s | database. p50 516 ms. p95 1107 ms. 100%. Direct pooled SQL connections over Virginia SSL (c=50, about 100 requests) |
| 11 | Prisma Postgres | 58 req/s | database. p50 338 ms. p95 1427 ms. 100%. Pooled connection manager stabilized burst without pool exhaustion |
| 12 | Pixeltable Compute | 56 req/s | compute. p50 783 ms. p95 1492 ms. 100%. In-engine route execution on shared Community cluster; 100% success rate |
| 13 | Turso libSQL | 31 req/s | database. p50 1225 ms. p95 1871 ms. 100%. Single remote writer lock in SQLite serializes high-concurrency writes |
| 14 | Modal | 27 req/s | compute. p50 1579 ms. p95 3113 ms. 100%. Serverless container queue scaling with container concurrency autoscaling |
| 15 | Pixeltable Ingest | 14 req/s | database. p50 2416 ms. p95 5695 ms. 100%. 100% success rate under 50-burst write spike with widened Nginx burst=100 delay=50 (was 94% with 6% 429) |
Extreme concurrency
c=100. Higher is better. Bar length is requests per second. Modal Async is about 100 completions; the other rows are about 200.
| Rank | Plan | Result | What was timed |
|---|---|---|---|
| 1 | Railway Postgres | 535.5 req/s | p50 152 ms. 0.37 s. 100%. Pooled SQL over the public TCP proxy. About 200 requests. max_connections=500 on that database. |
| 2 | Cloudflare Workers | 288.8 req/s | p50 225 ms. 0.69 s. 100%. Edge isolate response. About 200 requests. |
| 3 | Pixeltable Ingest (Async) | 169.6 req/s | p50 468 ms. 1.18 s. 100%. background=True HTTP response. About 200 requests. This is a different sample from the c=50 burst row at 96.6 req/s. |
| 4 | Convex | 144.5 req/s | p50 514 ms. 1.38 s. 100%. Document mutation. About 200 requests. |
| 5 | Render | 111.6 req/s | p50 800 ms. 1.79 s. 100%. Warm container HTTP. About 200 requests at 111.6 req/s, p50 800 ms. |
| 6 | Render Postgres | 103.1 req/s | p50 813 ms. 1.94 s. 100%. Pooled SQL over Virginia SSL. About 200 requests. A separate check, not this timed run, refused new sessions at connection slot 97. |
| 7 | Railway | 97.2 req/s | p50 673 ms. 2.06 s. 100%. Container HTTP. About 200 requests. |
| 8 | Neon Serverless PG | 73.2 req/s | p50 1211 ms. 2.73 s. 100%. SQL over the serverless proxy. About 200 requests. |
| 9 | Vercel | 70.7 req/s | p50 690 ms. 2.83 s. 100%. Serverless function invocations. About 200 requests. |
| 10 | Supabase PostgREST | 67.5 req/s | p50 1208 ms. 2.97 s. 100%. PostgREST writes. About 200 requests. |
| 11 | Pixeltable Compute | 49.3 req/s | p50 1663 ms. 4.06 s. 100%. Stateless /ingest/titles. About 200 requests. |
| 12 | Modal | 44.9 req/s | p50 1877 ms. 4.46 s. 100%. Container POST. About 200 requests. |
| 13 | Turso libSQL | 31.4 req/s | p50 2604 ms. 6.36 s. 100%. Remote SQLite writes. About 200 requests. The single writer serializes them. |
| 14 | Modal Async (.spawn) | 20.5 req/s | p50 2167 ms. 4.87 s. 100%. background_task.spawn(). 20.54 req/s over 4.87 s is about 100 completed requests, not 200. p50 2167 ms. |
| 15 | Pixeltable Ingest (Sync) | 13.8 req/s | p50 4980 ms. 14.48 s. 100%. Synchronous insert with the computed-column DAG. About 200 requests. |
Not timed: Prisma Postgres
Separate checks
Microburst rate limit
500 requests, c=350
443 responses were 200. 57 were HTTP 429 RATE_LIMITED with retry_after 1 s.
The ingress buffer is burst=100 delay=50.
Decompression bomb
625 megapixels
HTTP 400 in 0.63 s. Image size exceeds the 178,956,970 pixel limit.
The image decoder rejects the file before the full bitmap is allocated.
Synchronous insert pool
250 clients
250 of 250 returned 200, at 13.2 req/s.
The connection pool queued commits. This run recorded no dropped sockets.
Render Postgres connection ceiling
100 client connections
New sessions were refused at slot 97: remaining connection slots are reserved for superuser.
That database’s max_connections is 100, with superuser slots held back. This is a different run from the pooled c=100 timing.
Async ingest at c=200
400 requests, c=200
400 of 400 returned 200, at 63.1 req/s.
The HTTP handlers queued work. This run recorded no dropped sockets.
Async ingest at c=100
About 200 requests, c=100
169.6 req/s, p50 468 ms, 200 of 200 returned 200.
The HTTP response returns a job id. The measured p50 of that response is 468 ms, not a few milliseconds.
Media throughput
Higher is better. Bar length is videos per second.
| Rank | Plan | Result | What was timed |
|---|---|---|---|
| 1 | Railway (Container) | 37.1 vid/s | In-memory PyAV decode + thumbnail generation. p50 131 ms. Pure ephemeral computation in Docker container. Zero database persistence or vector search. |
| 2 | Render (Container) | 14.6 vid/s | In-memory PyAV decode + thumbnail generation. p50 285 ms. Ephemeral container processing. Zero database persistence or vector search. |
| 3 | Supabase Storage | 10.0 vid/s | Raw S3-compatible video upload to bucket. p50 401 ms. Stores raw video file bytes only; cannot decode frames, transcribe Whisper, or index embeddings. |
| 4 | Vercel (AWS Lambda) | 5.6 vid/s | PyAV video decode on serverless function. p50 687 ms. Lambda cold starts and payload ceilings (4.5 MB body limit triggers 413 Payload Too Large on 1080p). |
| 5 | Pixeltable Cloud (Async Queue) | 3.3 vid/s | Non-blocking async job submission + background engine drain. p50 72 ms. Immediate HTTP return (72ms submission p50); background workers decode PyAV and maintain embedding indexes. |
| 6 | Pixeltable Cloud (Sync Video) | 1.5 vid/s | Full synchronous PyAV decode + R2 storage + versioned DB insert. p50 1966 ms. Full pipeline executes in-schema: video validation, frame decode, thumbnail upload to R2, PostgreSQL row insert. |
Not timed: Cloudflare, Modal, Neon, Turso, Prisma Postgres, Convex
Same pipeline, one file
One schema, or several services
Open a row for the full note.
Eliminates 3-5 external microservices, glue code, and synchronization failures.
Absorbs concurrency burst spikes up to 96.6 req/s with zero external queue infrastructure to configure or pay for.
Decoders like ffmpeg and OpenCV execute natively within the database lifecycle.
Every writer automatically triggers transformations without manual job dispatch code.
Eliminates index desynchronization and orphaned vector rows.
Prevents database downtime, connection drops, and partial migration failures.
Free tier applications don’t go dark or fail health checks unexpectedly.
Avoids sudden production outages caused by monthly trial credit exhaustion.
Zero risk of catastrophic 30-day database deletion.
Allows end-to-end multimodal AI pipelines without hopping to external GPU clusters.
Drastically lowers total cost of ownership (TCO) and operational surface area.
Methodology
Equal Geographic Footprint (US-East)
All live cloud benchmarks were executed from an independent client residing in AWS US-East (N. Virginia), targeting each provider’s respective US-East region to isolate cloud engine performance from transcontinental network variance.
Free-plan endpoints, no negotiated exemption
Each timed endpoint ran on that provider’s published free plan. A provider appears on a chart only when that path was timed. After the Nginx burst change (burst=100, delay=50), the recorded Pixeltable ingest burst had no 429s. Turso’s burst reflects its single-writer lock.
Payloads are small, and they are not one schema
Supabase rows are title and video_url. Neon, Turso, and Prisma rows are id, title, and body. Compute endpoints accept a title and body and do not persist a row. Compare a chart within one path. Do not treat a Supabase write and a Neon write as the same statement.
Code Complexity & Frankenstack Tax
Line counts and service counts were determined from complete working implementations of the same multimodal application (video frame extraction, audio transcription with Whisper, CLIP embeddings, and semantic query). Non-blank, non-comment lines of code.
Dormancy is part of the free plan
Render spins a free web service down after 15 minutes. Neon suspends compute after about 5 minutes of idle time. Supabase pauses a free project after 7 days without activity. Those clocks are properties of the plans. This page does not ping them.
Questions
Were all 11 plans timed on every chart?
No. Eleven free plans are compared on storage, compute, and dormancy. A latency, burst, or batch chart includes only the providers timed on that path.
Do these numbers update themselves?
No. The charts are one recorded run from a client in AWS US-East. To publish a new run, execute python3 scripts/mega_shootout.py on your machine and copy the figures you trust into this file.
Does Pixeltable replace these databases?
No. Use Neon, Supabase, Prisma Postgres, or Turso when the app needs their database. Use Pixeltable when inserting a row should run a media pipeline. The two can sit side by side.
How do these free tiers behave under extreme concurrency (c=100) or large payloads?
At c=100, Pixeltable Ingest Async completed about 200 requests at 169.6 req/s, p50 468 ms. Render’s web service on that same shape completed about 200 requests at 111.6 req/s, p50 800 ms. The c=50 async burst is a different sample, 96.6 req/s over 1.04 s. Modal Async (.spawn) is also a different sample: 20.54 req/s over 4.87 s, about 100 completions, p50 2167 ms. Vercel rejects a payload above 4.5 MB with HTTP 413. Pixeltable Cloud accepts uploads up to 100 MB.
How do Railway Postgres and Render Postgres compare on this run?
Railway Postgres point reads were 22.1 ms and the 100-row batch was 1,107 rows/s. At c=100 it completed about 200 SQL requests at 535.5 req/s. Render Postgres point reads were 66.1 ms and the batch was 603 rows/s. Its pooled c=100 run completed about 200 requests at 103.1 req/s. A separate Render check, opening 100 direct connections, was refused at slot 97.
What did the breaking-point checks record?
500 requests at c=350 produced 443 responses of 200 and 57 of HTTP 429. A 25,000 by 25,000 PNG was rejected in 0.63 s. 250 synchronous inserts all returned 200, at 13.2 req/s. 400 async requests at c=200 all returned 200, at 63.1 req/s.
pip install 'pixeltable[serve]'