About Stackra
Stackra is a free website audit tool for small and mid-sized businesses. Our own site is a React single-page app served by Express, around 42 marketing and blog routes in total. We hit this problem on our own site, which is why we have a story to tell about it.
Why we did not switch to Next.js or Remix
Server-side rendering frameworks like Next.js, Remix, and Nuxt solve the same problem by rendering HTML on a Node server for every request. They are the industry default answer. We considered them and decided against, for four reasons.
- Our marketing pages are essentially static. The same HTML works for every visitor. SSR's main value, dynamic per-request HTML, did not apply to anything we needed crawlers to see.
- Migrating to Next.js or Remix is a real architectural change: routing rewrite, data-fetching refactor, layout migration. Adding a build-time prerender step on top of our existing setup is additive, not architectural.
- Static HTML on disk is the cheapest, fastest, most cacheable response a server can produce. SSR adds a render server we have to run, monitor, and pay for.
- The pages on Stackra that genuinely need dynamism, like the report viewer and dashboard, are intentionally not indexable. They never needed SSR for SEO.
Effort and footprint, side by side
The honest cost comparison between migrating to SSR and the prerender setup we shipped. The prerender numbers are actuals from our codebase. The SSR numbers are a realistic estimate of migrating a Vite + React app of similar surface size.
| Dimension | SSR (Next.js / Remix) | Prerender (what we shipped) |
|---|---|---|
| Initial dev time | Weeks | 1-2 days |
| Files changed | Hundreds across routing, layouts, data hooks | 3 in the core path; a handful more for validation and route centralization |
| Production infrastructure | Node render server (often per region) | Static files served by the existing Express layer |
| Per-request CPU cost | Render every request | Zero. Send a file. |
| Build-time cost | Standard bundle build | +30-60 seconds for the headless browser pass |
| Cache strategy | Edge cache + revalidation rules | HTML on disk, no special cache layer |
| Failure modes you'll hit | Render server outages, hydration mismatches, render-time memory leaks | Route-list drift, missing API stubs, headless browser quirks |
| Reversibility | Hard. SSR changes data fetching everywhere. | Easy. Delete the script and the static.ts check. |
Effort estimates assume an existing Vite + React SPA of similar surface size to Stackra (around 42 indexable routes including the blog). Modern edge runtimes have lowered SSR's operational cost; the trade-off is real but smaller than it used to be.
How to know if this fits your site
Match the shape of your site to the rendering model. Use this as a starting point, not an absolute rule.
| Site shape | Prerender | SSR | Why |
|---|---|---|---|
| Marketing site (a few hundred routes) | Recommended | Overkill | Same HTML works for everyone. SSR's per-request value does not apply. |
| Blog with steady cadence | Recommended | Not needed | Deploy-per-change cadence is fine. Static files are the cheapest response. |
| Documentation site, frequent updates | Workable | Recommended | Hundreds of routes plus deploy-on-merge cadence stresses prerender build times. |
| E-commerce, hundreds of SKUs | Workable | Recommended | Either works. SSR wins if inventory or pricing changes between deploys. |
| E-commerce, tens of thousands of SKUs | Top SKUs only | Recommended | Build-time render of every variant is impractical. Hybrid often makes sense. |
| News, live events, hourly updates | Not viable | Recommended | Deploy-per-update is infeasible. Per-request rendering is the only honest answer. |
| Personalized or auth-aware indexable pages | Not viable | Recommended | HTML varies per visitor or per logged-in user. Per-request render needed. |
| SaaS product behind auth | Irrelevant | Irrelevant | Not indexable by design. Pick on operational preference; SEO is not the deciding factor. |
| Already on Next.js, Remix, or Nuxt | Available | One config flag | Migration cost is zero in either direction. |
"Recommended" means: this is the default unless you have a specific reason otherwise. "Workable" means: it can work, but the other column is usually less painful at this scale.
What we'd tell another small team
Two lessons that did not make it into the pain points:
- Pick the rendering model that matches the shape of your site, not the framework with the loudest fan club. Most marketing surfaces do not need SSR.
- Test like a crawler. The fastest way to find out what AI tools see is to run `curl` against your own pages and look at the raw response. If the headline is not there, the page is invisible.
Methodology and verification
- Run a free Stackra audit →
Check whether your own site renders the content crawlers and AI fetchers actually need to see.
- Read the related blog post →
A shorter, decision-focused summary of the same story.