SSR is a luxury, not a default
Next.js docs push Server Components everywhere. They rarely talk about the cost implications of rendering every request on the server.
The docs say: Use Server Components by default
And they're right — from a DX and performance perspective. Server Components reduce client-side JavaScript, allow direct database access, and keep secrets on the server. The mental model is clean.
But here's what the docs skip: every server-rendered request costs money. SSR means your server (or serverless function) runs code for every single page view. At 10k visitors a month, nobody cares.
At 1M? You're paying for 1M function invocations, 1M units of compute time, and 1M origin requests that bypass your CDN cache.
The decision tree nobody shows you
Ask yourself three questions before choosing SSR: Does the content change per-user or per-request? If not, SSG or ISR is almost always cheaper. The data is the same for everyone — why compute it fresh each time? Can the data be stale for 60 seconds? Even 'dynamic' content often doesn't need real-time freshness. A 60-second ISR revalidation means at most 1 origin hit per minute instead of thousands.
Is personalization truly per-request? Often you can split the page: static shell (SSG) + client-side data fetching for personalized parts. This is the pattern behind many production Next.js apps at scale.
SSG: the cheapest option that works for most sites
Static Site Generation means your pages are built once at build time and served as plain HTML files. The CDN handles everything. There's no server, no function invocation, no compute cost per visitor.
The entire HostCost site is statically generated — output: 'export' in next.config.ts. Every page is a plain HTML file. Our hosting cost is effectively $0 (for our current static-export setup, on a free or very cheap static host).
For content sites, documentation, marketing pages, dashboards with client-side data fetching, portfolios, blogs — SSG is the answer. The only things you need SSR for are truly dynamic, per-request content: authenticated pages, real-time data, A/B testing at the edge, or dynamic OG images.
The hidden cost of prefetch={true}
Here's a detail most developers miss: Next.js Link prefetch is enabled by default. When a Link enters the viewport, Next.js prefetches its route. On a page with 50 links visible, that's 50 prefetch requests firing on page load.
For SSG pages, these are cheap CDN hits. For SSR pages, each prefetch triggers a server-side render. A list page showing 50 product cards with SSR detail pages? That's 50 server function invocations before the user clicks anything.
Set prefetch={false} on your Links and prefetch only on hover with a debounce. Or better yet, use SSG for list items and fetch details client-side.
ISR: the middle ground
Incremental Static Regeneration is the bridge: pages are statically generated but can revalidate on a schedule. A 60-second revalidation means at most 1 server render per minute per page, regardless of traffic. 1M visitors see a cached page; only the first request after the revalidation window triggers a rebuild.
ISR requires a server runtime though (it doesn't work with output: 'export'), so you're on Vercel, a self-hosted Node server, or a platform that supports it. The cost is dramatically lower than full SSR but not zero.
What to do right now
Audit your pages: which ones actually need server-side data? Move everything else to SSG or ISR. Set prefetch={false} on all Links — add hover-based prefetching only where it matters. If you're building a content site, portfolio, docs, or marketing page: use output: 'export'.
It's the cheapest, fastest, most portable option. If you need dynamic data: fetch it client-side in a 'use client' component. The page shell can still be static.
Want to see these principles in action?