Skip to main content

ostr.io vs SSR

Dynamic rendering vs SSR - which one should you ship?

Dynamic rendering (pre-rendering for crawlers) vs server-side rendering: cost, complexity, SEO outcomes, and when to pick each approach.

Updated

Choose ostr.io if

  • Crawler traffic is a meaningful share of total hits and you want to isolate its cost.
  • You run a mature SPA (React, Vue, Svelte, Angular) that SSR migration would rewrite from the ground up.
  • You want a hybrid route model where only freshness-critical URLs keep SSR.
  • You need framework-independent rendering — multiple frontends behind one domain.

SSR might work if

  • You are starting a new Next.js / Nuxt / SvelteKit app and SSR is the framework default.
  • Content is personalized per-user and cannot be cached meaningfully.
  • The same HTML must stay real-time for both users and crawlers on the URLs that matter most.
  • Your team is already paying for SSR infrastructure and crawler traffic is low (< 5%).
Head-to-head

Dynamic rendering vs SSR — side by side

Both approaches produce crawlable HTML. Dynamic rendering separates the rendering concern from the user-facing runtime; SSR couples them inside the framework.

Dimension
BestDynamic rendering
Server-side rendering
Framework couplingFramework-agnosticTied to framework runtime
Cost modelFixed per-tierPer-request compute
Cold startNone (pre-rendered)200-600ms lambda cold start
Content freshnessCache TTL boundedReal-time per request
PersonalizationCrawler-facing onlyFull per-user logic
Migration costMiddleware snippetFramework migration
Crawler-traffic cost isolationIsolated in cacheHits origin every time
Hybrid deployment fitEasy to apply by route classPossible, but less flexible
AI crawler readinessStable crawler-facing HTMLDepends on runtime cost tolerance
Greenfield developer experienceBest for existing appsBest when chosen from day one
Route-level personalizationLimited to crawler-facing cacheFull request-time logic

A 3-question decision framework

First: is the content the same for every visitor? If yes, dynamic rendering is nearly always cheaper and simpler. If content is user-personalized, SSR or CSR with hydration is the fit. Teams still deciding where that line sits should compare this page with ostr.io vs Vercel SSR.

Second: is the crawler traffic budget predictable? If crawler volume spikes after a sitemap push or AI crawler discovery, pre-rendering isolates the cost. SSR makes crawler volume directly visible on your origin bill, which is why JavaScript rendering cost matters here.

Third: is framework migration a blocker? If rewriting the SPA to SSR would take months, dynamic rendering is the pragmatic layer that unlocks SEO without a rewrite.

Decision tree by content type

Use SSR when the route must compute user-specific state before the first byte: account dashboards, private pricing, checkout, geo-sensitive availability, or pages where auth changes the main content. Use dynamic rendering when the crawler only needs stable public HTML: marketing pages, documentation, changelogs, category pages, public listings, and long-tail content archives.

The catch is that most sites are mixed estates, not pure examples from framework docs. A SaaS app can have authenticated dashboards, public docs, changelogs, and marketing pages on one domain. In that situation the right answer is usually route classification, not a platform-wide ideological choice. That is also why SaaS and ecommerce teams often end up with a hybrid model.

Most mature sites run both

The typical mature stack is: SSR or ISR for the top 1% of pages (homepage, top categories, top product pages) + dynamic rendering for the long tail. This lets teams optimize freshness where freshness matters and cost where it does not. That split is especially common on SaaS and ecommerce stacks.

The two layers do not conflict. Dynamic rendering's bot-detection middleware simply forwards bot traffic past the SSR layer to the pre-rendered cache.

In practice, teams that keep this split explicit make better trade-offs. They know which URLs earn the cost of real-time rendering and which URLs only need clean, indexable HTML on first fetch. Once that rule exists, crawler economics stop leaking into every framework decision.

Where SSG and ISR fit in the same landscape

SSG is the cleanest answer when the content graph is small, stable, and cheap to rebuild. ISR extends that model when the graph is still manageable but changes often enough that full rebuilds become painful. Dynamic rendering enters when the site is already client-rendered, when the URL graph grows faster than rebuild logic can handle, or when crawler-cost isolation matters more than framework purity.

ISR sits closer to SSR than to dynamic rendering because the first request after expiry still depends on application runtime. That matters for cost modeling. If the route is revisited by crawlers far more often than by humans, ISR still pushes bot demand onto origin infrastructure. Dynamic rendering removes that pressure by serving a crawler-facing cache instead.

The real decision is cost over time, not page-speed ideology

Teams often frame this as a philosophical debate about rendering models. In practice it is a budget and operations decision: which requests must be real-time, and which requests only need stable crawler-facing HTML? Once the URL graph grows, that question matters more than purity.

If the site is moving toward 100k+ URLs, pair this page with large sites (100k+ pages). If the concern is build-vs-buy at the edge, pair it with ostr.io vs Cloudflare.

Freshness, cost, and migration effort rarely line up neatly. SSR usually wins on freshness, dynamic rendering usually wins on migration speed for an existing SPA, and the long-tail cost curve usually favors dynamic rendering once crawler demand becomes material. The right architecture depends on which constraint hurts first.

When each model is the wrong fit

Dynamic rendering is the wrong fit when the important indexed HTML is personalized at request time or when parity between the live app and crawler snapshot cannot be kept stable. SSR is the wrong fit when crawler traffic forces the application layer to do expensive work on pages that do not need per-request computation for real users.

Worth noting: many bad architecture decisions come from choosing too early and applying the choice too broadly. If the app is already live and SEO is blocked now, dynamic rendering often buys time and visibility first. If the app is greenfield and built around public, freshness-critical routes, SSR may be the cleaner starting point.

Cloaking policy - dynamic rendering is still allowed

Google's dynamic rendering documentation has been stable since 2018. Serving substantially the same content to bots and users is the defining line; manipulating rankings by showing different content is cloaking.

The practical rule is: if a user disables JavaScript and sees the same text, headings, prices, reviews and structured data that the pre-rendered snapshot contains, the site is on the correct side of the line. For implementation-level details, follow pre-render cache headers and parity checks in the advanced guides.

Migration

Hybrid: SSR for top pages + dynamic rendering for long tail

Common pattern in production. Keep SSR for routes that need freshness, delegate the rest to a pre-rendered cache.

middleware.ts
typescript
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
const BOT_REGEX = /bot|crawler|spider|googlebot|bingbot|applebot|gptbot|claudebot/i;
const SSR_ROUTES = /^\/(?:|products|cart|checkout)$/;
export function middleware(req: NextRequest) {
const ua = req.headers.get("user-agent") ?? "";
const isBot = BOT_REGEX.test(ua);
const isFresh = SSR_ROUTES.test(req.nextUrl.pathname);
// Human users: SSR for everything, no middleware changes
if (!isBot) return NextResponse.next();
// Bots on freshness-critical routes: keep SSR
if (isFresh) return NextResponse.next();
// Bots on the long tail: forward to pre-rendered cache
const render = new URL(
`https://render.ostr.io/render?url=${encodeURIComponent(req.nextUrl.toString())}`,
);
return NextResponse.rewrite(render);
}
export const config = { matcher: "/((?!_next|api|og|static).*)" };
FAQ

SSR vs ostr.io — questions engineers ask

No, as long as the pre-rendered HTML is substantially the same as the hydrated page. Google's documentation explicitly lists dynamic rendering as an accepted technique.

No. SEO outcomes depend on what reaches the crawler, not how it was generated. A well-configured dynamic rendering layer produces identical crawler-facing HTML to an SSR-rendered page, with lower origin cost.

Yes. Most mature sites do: SSR for the top 1% of pages where freshness matters, dynamic rendering for the long tail. The bot-detection middleware chooses the path per request.

SSG (static generation at build time) is the cheapest path when the content graph is small and changes infrequently. Once the content graph exceeds a few thousand pages or changes more than once a week, SSG build times and deploy complexity push teams toward SSR or dynamic rendering.

Classify routes by two tests: does the HTML need per-user or per-request freshness, and does the route receive material crawler demand? Keep SSR where both answers are yes. Use dynamic rendering where the HTML is public and stable enough to cache for crawlers.

It is still relevant in 2026 because many production estates are mixed: legacy SPA sections, newer SSR sections, docs, marketing pages, and crawler-heavy long tails on one domain. Dynamic rendering remains the fastest way to make the crawler-facing layer stable without rewriting the whole estate.

For public long-tail routes with heavy crawler traffic, dynamic rendering is usually cheaper because it isolates bot demand in cache. For a small set of freshness-critical routes, SSR can be the better trade because the same runtime serves both users and crawlers.

Yes. Google Web Rendering Service (WRS) consumes whatever HTML the URL returns. It does not distinguish between "SSR-produced HTML" and "snapshot-produced HTML." What matters is that the HTML is complete and stable.

Editorial trust

Written by ostr.io engineering team · Engineering Team. We build and run pre-rendering infrastructure for more than 200 engineering teams, which is where the numbers and code samples on this page come from.

Last updated . Editorial scope and review policy: About prerender.info.

Run this comparison against your own stack

prerender.info · pre-rendering for JS SEO

Switch to ostr.io — migration in 15 minutes