Skip to content

Benchmarks

One app, four platforms, one afternoon. We deployed the same Next.js + FastAPI + Postgres app to Rivtor, Vercel + Supabase, Railway and Render and timed each from India. Every result is on this page, including the two where Rivtor does not lead.

Measured from one MacBook on home broadband in India. Medians; lower is better in every row.

Results

Redeploy after a one-line change

Rivtor
8.7 s
Vercel + Supabase
15.9 s
Railway
62.3 s
Render
67.9 s

App → database, per querymedian of 10 calls

Rivtor
0.19 ms
Vercel + Supabase
1.77 ms
Railway
2.69 ms
Render
0.58 ms

Page load, total median2 rounds pooled, n = 40

Rivtor
238 ms
Vercel + Supabase
263 ms
Railway
309 ms
Render
314 ms

API call with a DB write, total median2 rounds pooled, n = 40

Rivtor
229 ms
Vercel + Supabase
225 ms
Railway
296 ms
Render
275 ms

Wake after sleepfirst API request

Rivtor
2.9 s
forced sleep; first page 3.7 s
Vercel + Supabase
0.31 s
did not sleep in 16 min
Railway
1.5 s
woken from App Sleeping; first page 1.6 s
Render
~60 s
per Render's docs, not measured

Page load and API figures are total time as a user waits for it, including DNS, TCP and TLS on a new connection, and are the median of two rounds of 20 requests pooled (40 per platform). App to database is timed inside the app, so the network to our client is not part of it.

Where Rivtor does not lead

  • API call with a database write: a tie. Vercel + Supabase answered in 225 ms against Rivtor's 229 ms, a gap of a few milliseconds in Vercel's favour. Vercel's Mumbai edge was also closer to our client (TCP connect median about 31 ms, against about 60 ms for Rivtor through Cloudflare).
  • Wake after sleep: Railway is faster. Railway woke from App Sleeping in 1.5 s; Rivtor took 2.9 s for the first API request and 3.7 s for the first page, because the page waits for both the web and API containers to start. Railway was about twice as fast.
  • Vercel's functions were still warm after 16 minutes without traffic, so its 0.31 s is not a wake time. Render was not measured: the benchmark stopped before its probe. Render's documentation says free services take about a minute to spin back up.

As bars

The four rows that every platform completed, to scale within each chart. Wake after sleep is left out because the platforms were not in the same state when probed.

Redeploy after a one-line changeLower is better
  • Rivtor: 8.7 s
  • Vercel + Supabase: 15.9 s
  • Railway: 62.3 s
  • Render: 67.9 s
App → database, per query (median of 10 calls)Lower is better
  • Rivtor: 0.19 ms
  • Vercel + Supabase: 1.77 ms
  • Railway: 2.69 ms
  • Render: 0.58 ms
Page load, total median (2 rounds pooled, n = 40)Lower is better
  • Rivtor: 238 ms
  • Vercel + Supabase: 263 ms
  • Railway: 309 ms
  • Render: 314 ms
API call with a DB write, total median (2 rounds pooled, n = 40)Lower is better
  • Rivtor: 229 ms
  • Vercel + Supabase: 225 ms
  • Railway: 296 ms
  • Render: 275 ms

Method

  • The app. A FastAPI service with a psycopg connection pool and three endpoints: /health; /db, one UPDATE … RETURNING; and /db20, 20 sequential SELECT 1 timed inside the app. A Next.js page rendered on the server calls /db on every request. The app code is identical on every platform; only each platform's config files differ.
  • Timing. curl -w on the client. Total is time_total, what a user waits. Every request opens a new connection, so every total includes DNS, TCP and TLS.
  • Redeploy. The same comment line appended to api/main.py, deployed with each platform's normal workflow (its CLI; git push for Render), timed from the start of that command until the platform reported the new release live and /health answered 200. Only the API service was rebuilt on each platform.
  • Latency. Three warm-up requests, then 20 requests per endpoint, 0.2 s apart, one platform at a time. The round was run twice back to back; the table shows the median of both rounds pooled.
  • App to database. /db20 called 10 times; the median of the per-query time measured inside the app.
  • Wake after sleep. No traffic to any platform for 16 minutes, then the first request to the API and to the page, then one warm request. Rivtor free apps only sleep after 60 minutes idle, so its containers were stopped the same way its idle sleeper stops them before the probe.

Environment

Region, plan and database for each platform
PlatformRegionPlan and sizeDatabase
RivtorCentral India (Azure), Cloudflare in frontFree plan: api and web containers each 0.5 vCPU / 512 MBPostgres via PgBouncer on the same machine as the app
Vercel + SupabaseVercel bom1 (Mumbai) + Supabase ap-south-1 (Mumbai)Vercel Pro team, Next.js and Python functions in bom1 with default settingsSupabase in the same city, a different provider, via the Supavisor pooler
RailwaySingapore (asia-southeast1)Hobby plan, one replica per service, App Sleeping onRailway Postgres in the same project, over the private network
RenderSingapore, Cloudflare in frontFree instances: 0.1 CPU / 512 MB, spin down after 15 min idleRender free Postgres in the same region, over the internal URL

Client: one MacBook on home broadband in India, on 7 Nov 2026. Requests to Rivtor entered Cloudflare in Chandigarh (IXC). Railway and Render have no India region, so both ran in Singapore.

Caveats

  • Regions are not equal. Every request from India to Singapore pays a longer round trip (TCP connect median about 94 ms for Railway and 65 ms for Render, against 31 ms for Vercel in Mumbai and 60 ms for Rivtor through Cloudflare). Rivtor and Vercel + Supabase are the like-for-like pair for latency.
  • Plans are not equal. Rivtor ran on its free plan, Vercel on a Pro team, Railway on Hobby and Render on its free instances (0.1 CPU), so Render's numbers reflect its free tier, not its paid instances.
  • Vercel + Supabase spans two providers. The app to database hop leaves Vercel for Supabase in the same city, through the Supavisor pooler. On Rivtor, Postgres (through PgBouncer) sat on the same machine as the app.
  • Railway's page called its API over private networking, while Rivtor, Vercel and Render called the API's public URL (Rivtor's default wiring goes back out through Cloudflare). This favours Railway on page load.
  • Rivtor's wake was a forced sleep: its containers were stopped after the same 16 idle minutes and probed 20 s later. The other platforms were left to sleep, or not, on their own.
  • Render's wake was not measured. The ~60 s in the table is Render's published figure.
  • Redeploy timing differs slightly. Rivtor and Vercel were timed around a CLI that waits until live; Railway and Render by polling their deploy status every 2 s, which adds up to about 3 s of resolution. Rivtor and Railway reused build caches from earlier deploys.
  • One client, one afternoon, 20 samples per endpoint per round. TCP SYN retransmits on our client's path produced outliers of about 1.2 s on the two Cloudflare-fronted platforms, Rivtor and Render. Medians are barely moved by them; 90th percentiles are not, which is why this page reports medians.
  • The API opens its database pool at startup on every platform, so every wake includes connecting to Postgres.
  • First-deploy times are not shown: they were recovered from logs with different measurement windows per platform, so they are not comparable.

Reproduce it

The benchmark app lives in our repository under bench/h2h: api/ (FastAPI), web/ (Next.js) and platforms/ (the config each platform needs). To run the same protocol on your own accounts:

  1. Deploy api with a Postgres database, and web pointed at the API, to each platform in the region closest to you.
  2. From one machine, send three warm-up requests, then 20 requests 0.2 s apart to the page, /health and /db, timing each with curl -w '%{time_total}' on a new connection. Run it twice and take the median.
  3. Call /db20 ten times and take the median of its per_query_ms.
  4. Append one comment line to api/main.py, redeploy, and time it until /health answers 200 from the new release.
  5. Leave every platform idle long enough to sleep, then time the first request to the API and to the page.

Results depend heavily on where you are; from outside India the order may change. Rivtor's free plan and its sleep rules are on Limits.