Practical Guide to Nuxt SSG/ISR Pagination in Vue Storefront
Learn how Vue Storefront’s Nuxt integration pre‑renders the first product page, uses ISR for cache invalidation, and hydrates pagination state on the client. Includes a concrete example, trade‑offs, and a checklist to keep your catalog fresh and SEO‑friendly.
30 Jul 2026, 20:49 UTC

Problem: Pre‑rendering Product Pages with Pagination
When building a headless e‑commerce site with Vue Storefront (VSF) on Nuxt, you want static, SEO‑friendly product listings. However, product catalogs are large and change frequently. The challenge is to serve the first page of a paginated list as static HTML while keeping subsequent pages up‑to‑date without re‑building the entire site.
Thesis: Combine Nuxt’s SSG with Incremental Static Regeneration (ISR) and GraphQL pagination
Nuxt’s generate module creates static pages for each route, but only the first page of a paginated list is pre‑rendered by default. ISR hooks can trigger a regeneration of a page when the GraphQL cache changes, ensuring fresh data. Meanwhile, the useProduct composable automatically adds pagination parameters based on the current route, and client‑side hydration preserves pagination state via localStorage.
Section 1: Setting Up the Static Generation
Configure nuxt.config.js to generate product routes and expose the ISR hook:
export default {
generate: {
routes: async () => {
const { data } = await fetch('https:///products?limit=1')
return data.products.map(p => `/products/${p.slug}`)
},
fallback: false
},
hooks: {
generate: async (payload) => {
// Called after each generate run – useful for ISR
}
}
}
After running nuxt generate, check the /.nuxt/generate folder. You should see products directories containing index.html files for each slug. These files represent the first page (?page=1) of the product listing.
Section 2: ISR Hook for Cache Invalidation
When a product changes, the GraphQL endpoint emits a webhook. You can trigger a regeneration of the affected product page by calling:
curl -X POST https://yourdomain.com/api/nuxt-generate?slug=
Internally, Nuxt receives this request, re‑runs the generate hook for the specified route, and updates the static file. The ISR hook can also set appropriate Cache‑Control headers:
app.head = {
meta: [
{ httpEquiv: 'Cache-Control', content: 'public, max-age=300' }
]
}
Setting max‑age=300 (5 minutes) balances freshness and performance. After regeneration, the new static file is served for subsequent GET requests.
Section 3: Pagination Logic on the Client
VSF’s useProduct composable reads the page query parameter from the route and appends it to the GraphQL request:
const { page = 1 } = useRoute().query
const { data, pending } = useProduct({ limit: 20, offset: (page - 1) * 20 })
The first page is pre‑rendered; subsequent pages are fetched via AJAX. To keep the pagination state across page refreshes, the composable stores the current page in localStorage:
const pageKey = `pagination-${route.path}`
const storedPage = localStorage.getItem(pageKey)
if (storedPage) {
setRoute({ query: { ...route.query, page: storedPage } })
}
When the user navigates to a new page, the new page number is saved:
onPageChange = (newPage) => {
localStorage.setItem(pageKey, newPage)
navigateTo({ query: { ...route.query, page: newPage } })
}
Section 4: Trade‑offs and Limitations
- Only the first page is static. SEO crawlers will see only page 1 unless you pre‑render additional pages manually.
- ISR relies on webhooks. If the GraphQL service does not trigger a webhook after a product update, the cached page may become stale until the next manual regeneration.
- Nuxt 2 vs Nuxt 3 differences. The
generateAPI changed; migrating requires updating route definitions and the ISR hook implementation. - Client hydration timing. The first page loads instantly, but subsequent pages may experience a brief flash of loading UI while the AJAX request resolves.
Actionable Checklist
- Run
nuxt generateand verify static files exist for each product slug. - Configure the GraphQL webhook to call
/api/nuxt-generate?slug=…after a product update. - Set
Cache‑Controlheaders topublic, max‑age=300innuxt.config.js. - Test pagination: navigate to page 2, refresh, and confirm the page number persists.
- Monitor the
/.nuxt/generatefolder for new files after webhook triggers. - Optional: pre‑render additional pages by extending the
generate.routesfunction to include?page=2,?page=3, etc., if SEO for deeper pages is required.
Conclusion
By combining Nuxt’s static site generation with ISR and VSF’s GraphQL‑aware pagination, you can deliver fast, SEO‑friendly product listings that stay fresh with minimal rebuild overhead. Keep an eye on webhook reliability and consider pre‑rendering extra pages if deeper pagination is critical for your SEO strategy.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.