nextjs · tutorial · agents
Next.js SSR Slow on Vercel? Make It Instant
Server render plus cold start plus distant DB: 2s SSR. Warm PM2, local SQLite, edge cache — instant on flat. Fix inside.

The server-rendered page took two seconds
A landing page moved to SSR for SEO — server-rendered, fresh data, Google-happy. Then loaded: 2.1 seconds, blank white, while the function cold-booted (800ms), rendered React (400ms), and queried a database two regions away (900ms of travel).
SEO gained a point. Every human lost patience.
Worse: subsequent loads weren't much better. Warm functions still queried distant data per request (no colocation dividend), and traffic spikes reintroduced cold starts exactly when speed mattered most — launch day, demo day, the days slowness costs actual money.
Nextjs ssr slow isn't rendering being slow. It's rendering far away, cold, from distant data — three penalties stacked on one request.
SSR time anatomy, serverless vs flat
| Millisecond source | Vercel SSR | VPS PM2 + SQLite |
|---|---|---|
| Cold boot | 0–2,500 (idle scale-to-zero) | 0 (always warm) |
| React render | 200–500 | 50–150 (warm process) |
| Data queries | 100–900 (network legs) | 1–5 (local NVMe) |
| Total typical | 800–2,500 | 60–200 |
| Spike behavior | Worse (more colds) | Same (steady) |
Three things switching stacks teaches:
- Cold starts dominate averages. Median SSR looks fine in dashboards (warmed by crawlers and regulars); p95 tells the truth (real users arriving cold). Scale-to-zero saves money between visits and spends user patience on arrival — the exact tradeoff backwards for landing pages, where first impressions convert.
- Query legs dwarf render compute. My 400ms render against 900ms travel meant React optimization (memo, selective hydration) attacked 30% of the problem while colocation attacked 70%. Teams profile components for weeks while the database sits in another timezone. Distance first, diffing second.
- Spikes punish twice. Viral traffic triggers cold starts (new instances) plus throttled databases (connection storms) simultaneously — slowest pages exactly when most eyes watch. Flat servers absorb spikes at steady latency (same warm process, local data, edge cache in front). Popularity should reward, not lag.
The bandwidth post covered transfer. This one covers time-to-first-byte that users feel as quality.
Nextjs ssr slow cure
Warm server, local data, cached edge — each collapses one penalty completely.
Step 1 — Serve from always-warm processes.
Run the app under a process manager with two or more workers, so nothing scales to zero. Save the process list and enable start-on-boot, so the app is resurrected and warm within seconds after a reboot. The cold-boot term deletes from every equation, spikes included.
Always-warm costs idle CPU (pennies on flat hardware) and buys zero-cold latency forever. Serverless scale-to-zero optimizes bills between visits; warm processes optimize arrivals — pick by what converts (arrivals, always). Measure your own p95 before and after.
Step 2 — Colocate data with rendering.
Choose SQLite as the database and keep its file on the same disk as the app. Pages render from local disk while the process stays hot, so network legs that took hundreds of milliseconds become local reads.
Colocation deletes the biggest term (travel) instead of optimizing it — no poolers, no cross-region TLS, no AZ roulette per request. The latency-truth post priced legs; this applies it to SSR specifically. Render compute (the honest 50–150ms) remains — genuinely fast, honestly measured, improvable with normal React care.
Step 3 — Cache the edge, stream the rest.
Cloudflare: cache SSR output per URL (short TTLs: 60s pages, 5min content)
Next: streaming (Suspense boundaries) — shell paints instantly, data fills in
result: repeat views ~20ms edge hits; first views fast AND progressiveEdge caching converts repeat SSR into static-speed responses (CDN wisdom applied to dynamic pages); streaming converts first views from blank waits into progressive paints. Perceived instant plus actual fast — the combination that ends "slow SSR" complaints rather than relocating them. Cache durations encode freshness tolerance per route, reviewed quarterly.
It all holds together — server-rendered at static speed.
SSR timings, both homes
| Landing page SSR | Vercel serverless | VPS warm + local |
|---|---|---|
| Cold p95 | ~2,100ms | ~180ms |
| Warm median | ~700ms | ~90ms |
| Spike behavior | Degrades (colds return) | Steady |
| Edge-cached repeat | ~150ms | ~20ms |
| Monthly cost of speed | $20 + meters | $5 flat |
Worth saying plainly: warm servers idle expensively relative to zero (pennies daily that scale-to-zero saves) and edge-cached SSR needs freshness discipline (TTL choices per route, purge paths on updates). Priced against 2-second first impressions on landing pages: conversion math ends the debate before it starts. Warmth is cheap; first impressions are everything.
FAQ
Is nextjs ssr slow fix just "use static generation"?
Often yes, honestly: fully static content (marketing, docs, blogs) should pre-render at build (fastest possible, cacheable forever). SSR earns its keep on personalized/fresh pages (dashboards, priced listings, user content) — dynamic by necessity, not default.
Audit per route: static unless proven dynamic. Most "slow SSR" is static content rendered dynamically out of habit.
How do ISR and edge caching differ for SSR speed?
ISR pre-renders periodically (stale-while-revalidate semantics, origin builds on schedule); edge caching stores SSR output per request (freshness via TTL, purged on demand). ISR suits content rhythms (hourly/daily), edge suits traffic rhythms (cache what's hot).
Solo stacks: edge caching first (simpler, universal), ISR where rebuild schedules match editorial ones. Both beat uncached SSR by orders.
Should API routes feeding SSR live on the same box?
Yes — same-box API calls are function calls with extra steps (localhost, microseconds), cross-service APIs are network legs again (the disease returning through architecture). Colocate API + SSR + SQLite on one VPS: the whole request stays on NVMe and localhost.
Distribution is a scaling tool, not a default topology. One box until triggers say otherwise.
What about global users — VPS in one region vs Vercel edge?
Edge caching covers static-ish SSR worldwide (20ms repeats globally); dynamic-personalized SSR serves from one region plus streaming (acceptable to ~300ms intercontinental). True global-personalized needs regional presence (the geography trigger, honestly faced). Continental audiences: one box + edge.
Global audiences: edge-first design, regional data later. Geography graduates, never starts distributed.
Do React Server Components help SSR speed?
Yes structurally: components fetch colocated data without client round-trips (fewer waterfalls), stream progressively (perceived speed), and skip JS bundles for server-only parts (less hydration). RSC plus local SQLite is the fastest SSR shape available — server components reading local disk, streaming to edge cache. Architecture and placement compounding: modern React on flat hardware.
When is client-side rendering actually better than SSR?
Dashboards behind login (SEO irrelevant, interactivity paramount), highly personalized views (uncacheable anyway), and offline-capable tools (service workers over servers). SSR serves search engines and first impressions; CSR serves applications and interactions.
Route-level choice, not app-level religion. Render where each page's users actually benefit.
Keep reading
- Next.js App Router Slow First Click? Fix the 1-5s Delay — the client-side half of slow
- useRouter Feels Slow? Skip It on First Paint — navigation speed after SSR lands
- 0.1ms vs 35ms: The Latency Math That Picks SQLite — the leg math underneath it all
+ all the boring stuff (analytics, auth, SQLite ↔ Supabase, full marketplace, webhooks)
Command from your phone.
Built so autonomous AI agents build what you want without breaking what's already paying you.
- Built-in analytics — cookie-free mode, $0 forever, no PostHog bill
- SQLite ↔ Supabase: one setting, same field names
- Full digital marketplace & feedback boards included
- 3 payment rails: Stripe, LemonSqueezy & Dodo Payments
- Agent fences: lint gate, read-only data access, auto-rollback
- Ship from your phone via SSH & WireGuard/Tailscale in under a minute
$199
Get BoringPushOne-time payment · Lifetime updates · Unlimited projects.
Keep reading


