SSR vs SSG: Choosing the Right Rendering for Dynamic Dashboards vs Static Blogs
0 reputation · 29 Oct 2021, 16:49 UTC
0 reputation · 29 Oct 2021, 16:49 UTC
When building a Nuxt 3 site, developers often face the decision between Server‑Side Rendering (SSR) and Static Site Generation (SSG). SSR renders each request on the server, enabling real‑time, personalized data at the cost of per‑request latency. SSG pre‑builds pages at deploy time, delivering CDN‑cached responses that are lightning‑fast but require a rebuild to reflect content changes.
A common use case is a user‑specific dashboard that must always display fresh data, versus a blog or marketing page that rarely updates. The choice directly impacts user experience, infrastructure costs, and deployment workflow.
Another nuance is Nuxt 3’s catch‑all routing. When a static route (e.g., /blog) and a dynamic catch‑all route (e.g., /blog/*) coexist, the framework’s documentation does not specify which pattern takes precedence, leading to potential ambiguity in URL resolution.
Given these constraints, the key questions become:
/blog and /blog/*, which route will Nuxt 3 match first, and how does that affect navigation?35775 reputation · 29 Oct 2021, 23:27 UTC
Use SSR for user‑specific dashboards and SSG for blogs or marketing pages. In Nuxt 3, when both /blog and /blog/* exist, the static /blog route is expected to take precedence over the catch‑all. Cache headers on SSR responses are not applied automatically; you must configure them explicitly through routeRules or server middleware.
Well‑established: Nuxt 3 supports hybrid rendering via routeRules, allowing per‑route control of SSR, prerendering, and headers. SSG emits static HTML at build time, while SSR renders on each request. The X-Nuxt-Server-Rendered response header is a reliable signal for distinguishing server‑rendered from prerendered output.
Likely but version‑dependent: The file‑based router resolves concrete path segments before wildcard segments, so /blog wins over /blog/*. Routing internals can shift between minor releases, so confirm this in your exact Nuxt 3 version before relying on it in production.
export default defineNuxtConfig({
routeRules: {
// Dashboard: fresh, per‑request data
'/dashboard': { ssr: true },
'/dashboard/**': { ssr: true },
// Blog: pre‑rendered, CDN‑friendly
'/blog': { prerender: true },
'/blog/**': { prerender: true },
// Explicit cache control for SSR endpoints
'/api/**': { headers: { 'Cache-Control': 'no-store' } }
}
})If the dashboard data is identical for every user, swr or ISR‑style revalidation could reduce server load. If it is personalized, stick with ssr: true and suppress shared‑cache storage.
Because /blog is more specific, requests to /blog should resolve to pages/blog.vue rather than pages/blog/[...slug].vue. A catch‑all can still shadow deeper nested static routes if those files are placed inside the same dynamic directory. Keep static pages as siblings, not children, of the catch‑all folder, or test resolution after every structural change.
| Route type | Recommended header | Reason |
|---|---|---|
| Dashboard (SSR) | Cache-Control: no-store or private, no-cache | Prevent shared caches from serving another user’s data |
| Blog (SSG) | Cache-Control: public, max-age=… | Allow CDN edge caching of immutable HTML |
| API / data endpoints | Cache-Control: no-store | Ensure fresh payloads for client‑side updates |
nuxi dev (or build and preview) and request /blog; confirm it renders the static page, not the catch‑all.X-Nuxt-Server-Rendered and your custom Cache-Control values.Are you deploying to a long‑running Node server, an edge runtime, or a fully static host? Edge and static targets may restrict routeRules behavior or header manipulation, which affects whether SSR is viable for the dashboard or whether you need a separate API layer.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.