Hook — 05 : 41 a.m., Florianópolis ↔ Santo Domingo stand-up
Ocean mist billowed past my Brazilian hostel window as Ana, dialing in from Santo Domingo, sighed: “Our marketing microsite takes five seconds on 3 G and Google’s crawling half the pages.” Her SPA shipped client-side JavaScript only, forcing every visitor to download a chunky bundle before seeing any content. We pivoted on the spot—swapped the project to Nuxt’s Static Site Generation (SSG) mode, configured dynamic routes to pre-render 800 blog posts, and deployed to Netlify’s global edge. First paint dropped below one second, SEO warnings vanished, and Ana still made her morning kite-surf lesson. That tropical rescue anchors today’s exploration of SSG with Nuxt: why, when, and exactly how to configure it.


Why SSG Still Wins in 2025

Search engines, social previews, and bandwidth-limited users all prefer immediate HTML. Static pages:

Nuxt’s SSG pipeline lets us keep single-file components, Composition API hooks, and Vue.js devtools while delivering cache-friendly HTML. Perfect for blogs, docs, landing pages, catalogs, or documentation portals your distributed team can preview offline on shaky hostel Wi-Fi.


How Nuxt Generates Static Sites

  1. Build phase — Vite bundles Vue.js code.
  2. Prerender phase — Nuxt crawls every route, runs useAsyncData on the server, and saves the HTML + payload JSON to dist/.
  3. Deploy phase — Upload the folder to Netlify, Vercel, GitHub Pages, S3 + CloudFront, or even an Nginx container.
  4. Runtime — The CDN serves complete pages; the browser hydrates them, turning static markup into live Vue components.

If content changes often, Nuxt’s Incremental Static Regeneration (ISR) lets you rebuild a single page on request—more on that below.


Project Setup from Scratch

bashCopyEditnpx nuxi init nuxt-ssg-demo
cd nuxt-ssg-demo
npm install

Enable SSG in config:

tsCopyEdit// nuxt.config.ts
export default defineNuxtConfig({
  ssr: true,               // keep true; SSG relies on SSR at build time
  nitro: { preset: 'static' }, // hints for deploy platforms
});

Launch dev server:

bashCopyEditnpm run dev

Even in dev, Nuxt simulates SSG by prefetching data server-side.


Defining Static Routes

Nuxt automatically prerenders:

Example blog directory:

cssCopyEditcontent/
 ├─ post-1.md
 ├─ post-2.md

Tell Nuxt to generate each slug:

tsCopyEdit// nuxt.config.ts
import fs from 'node:fs';

export default defineNuxtConfig({
  nitro: { preset: 'static' },
  prerender: {
    routes: fs
      .readdirSync('content')
      .map(f => '/blog/' + f.replace('.md', '')),
  },
});

Run:

bashCopyEditnpm run generate

dist/ now contains /blog/post-1/index.html, /blog/post-2/index.html, plus /blog/post-1.payload.js—hydration data inlined by Nuxt.


Hybrid Builds with Route Rules

Not every page suits SSG. Mix modes effortlessly:

tsCopyEditexport default defineNuxtConfig({
  routeRules: {
    '/blog/**': { static: true },         // full SSG
    '/dashboard/**': { ssr: false },      // pure CSR (auth-gated)
    '/': { static: true, swr: true },     // SSG + stale-while-revalidate
  },
});

Edge functions rebuild SWR pages after cache expiry—great for product listings that change hourly, not per request.


Hands-On Example: Incremental Static Regeneration

Enable on-demand rebuild:

tsCopyEdit// server/api/revalidate.post.ts
export default defineEventHandler(async event => {
  const body = await readBody(event);
  if (body.secret !== process.env.REVALIDATE_TOKEN) throw createError({ status: 401 });
  await $fetch('/api/_nitro/revalidate', { method: 'POST', body: { path: body.path } });
  return { revalidated: body.path };
});

Webhook your CMS to call this endpoint on publish; Nuxt regenerates just that page, leaving the rest untouched.


Remote-Work Insight Box

During a sprint in Cartagena we migrated a 2 000-page docs site. Full builds once took 8 minutes—painful when power blipped. We flipped on ISR, regenerating only updated sections; merge-to-preview dropped to 30 seconds, making code reviews possible from cafés with diesel generator backup.


Performance & Accessibility Checkpoints


Common Pitfalls & Swift Fixes

IssueReasonFix
Missing dynamic pagesForgot to list routesAdd them in prerender.routes or use payloadExtraction: false
Flash of undefined dataUsing useFetch() (client) instead of useAsyncData() (SSR)Swap composable—SSR renders first
Large payload filesJSON too heavyNormalize lists, compress images, lazy-load non-critical data
404 on refresh for dynamic routes on NetlifyMissing redirect rulesAdd _redirects with /* /index.html 200 when using browsers-history

Call-Out Reference Table

Tool / ConceptOne-liner Purpose
nuxi generateBuilds static site into /dist
prerender.routesEnumerate dynamic paths for SSG
routeRulesMix SSG, SSR, CSR per path
ISR (swr:true)Rebuild page on first stale request
nitro preset 'static'Optimizes output for static hosts

Must-Know CLI Commands

CommandWhy You Need It
npm run generateProduce static artifacts
npx serve distPreview locally
netlify deploy --prodPush to global CDN
nuxi cleanupRemove stale .nuxt cache when switching modes

Diagram Sketch (text)

Sanity publishes → webhook hits /api/revalidate → Nitro regenerates /blog/my-post → uploads to S3 → CloudFront invalidates single path → next visitor receives new HTML under 50 ms.


Wrap-Up

Static Site Generation pairs the developer joy of Vue.js with the speed and simplicity of plain HTML. By leaning on Nuxt’s declarative config—nitro preset, prerender.routes, and routeRules—you can tailor rendering per page, shrink hosting bills, and delight users browsing on prepaid data plans from Mexico to Colombia.

Curious about ISR tokens, markdown pipelines, or edge deployments? Drop your questions below; I’ll respond between flights and late-night arepa sessions.

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x