Looking to supercharge your Nuxt 3 application with lightning-fast page loads? Pre-rendering (or Static Site Generation) might be exactly what you need. In this guide, I'll dive deep into how you can leverage Nuxt 3 and its Nitro server engine to pre-render dynamic routes like a pro.
Why Pre-rendering Matters
Pre-rendering transforms your dynamic Nuxt app into static HTML files at build time, which means:
- ⚡ Ultra-fast page loads (CDN-ready!)
- 🔒 Improved security with fewer server dependencies
- 💰 Lower hosting costs (static hosting is cheap!)
Understanding Dynamic Routes in Nuxt 3
Before we jump into pre-rendering strategies, let's clarify what dynamic routes are. In Nuxt 3, dynamic pages are created in the /pages
directory using bracket syntax:
/pages/blog/[slug].vue // Creates dynamic routes like /blog/my-post
These routes typically depend on dynamic data (like content from a CMS or database), making them particularly challenging to pre-render.
5 Powerful Ways to Pre-render Dynamic Routes
1. Explicit Route Declaration
The most straightforward approach is manually listing your dynamic routes in the nuxt.config.ts
file:
export default defineNuxtConfig({ nitro: { prerender: { routes: ["/blog/first-post", "/blog/second-post"], ignore: ["/admin"] }, }, })
Best for: Small sites with a limited number of known routes.
2. Dynamic Route Discovery with Lifecycle Hooks
When your routes come from an external data source, automate the process with Nuxt's lifecycle hooks:
export default defineNuxtConfig({ hooks: { async 'prerender:routes'(ctx) { const posts = await fetch("https://my-api.com/posts").then(res => res.json()); // Add each post's URL to the pre-rendering queue for (const post of posts) { ctx.routes.add(`/blog/${post.slug}`); } } } })
Alternatively, you can use the nitro:config
hook:
export default defineNuxtConfig({ hooks: { async 'nitro:config'(nitroConfig) { if (nitroConfig.dev) return; const routes = await fetchDynamicRoutes(); nitroConfig.prerender = nitroConfig.prerender || {}; nitroConfig.prerender.routes = [ ...(nitroConfig.prerender.routes || []), ...routes ]; } } });
Best for: Sites with content from APIs, CMS platforms, or databases.
3. Automatic Crawling with crawlLinks
Let Nitro discover and pre-render your routes automatically by enabling the crawl feature:
export default defineNuxtConfig({ nitro: { prerender: { crawlLinks: true, routes: ["/"], ignore: ["/api", "/admin"] }, }, })
The crawler starts from your specified routes (like the homepage) and follows all internal links it finds in the HTML.
Best for: Sites with good internal linking and discoverable content.
Pro tip: The crawler won't find routes that are loaded lazily or via JavaScript, so combine this with methods 1 or 2 for comprehensive coverage!
4. Route Rules for Granular Control
Nuxt 3 offers powerful route rules that let you control pre-rendering at a pattern level:
export default defineNuxtConfig({ routeRules: { '/blog/**': { prerender: true }, '/products/**': { prerender: true }, '/admin/**': { prerender: false } } });
You can even specify pre-rendering directly in your page components:
<script setup> defineRouteRules({ prerender: true }); </script>
Best for: Applications with mixed rendering needs (some static, some server-rendered).
5. Programmatic Hints with prerenderRoutes
Use the prerenderRoutes
utility within your components or scripts to add routes during the build process:
<script setup> // This will add the route to pre-rendering at build time prerenderRoutes(['/sitemap.xml', '/products/special-offer']); </script>
Best for: Adding routes that might be missed by other methods, especially from deeply nested components.
Best Practices for Pre-rendering Success
Combine strategies - Use crawling for discoverable content and explicit routes for everything else.
Verify your build output - After running
nuxi generate
, check your.output/public
directory to ensure all expected HTML files were generated.Handle data fetching correctly - Make sure your
useFetch
oruseAsyncData
calls work both during pre-rendering and on client navigation.Don't forget about pagination - Explicitly pre-render paginated routes that the crawler might miss.
Monitor build times - Pre-rendering large numbers of pages can significantly increase build times. For very large sites, consider partial pre-rendering of important pages.
Common Pitfalls to Avoid
Crawler limitations: The crawler only finds links in the initial HTML. Routes loaded via AJAX or displayed conditionally might be missed.
API data staleness: Pre-rendered routes reflect data at build time. For frequently changing data, consider server-side rendering instead.
Environment variables: Make sure all required API keys are available during the build process.
Incorrect route patterns: Be careful with your glob patterns in route rules to avoid missing important pages.
Real-world Example: Blog with Categories and Tags
Here's how you might handle pre-rendering for a blog with multiple dynamic route parameters:
// nuxt.config.ts export default defineNuxtConfig({ nitro: { prerender: { crawlLinks: true, routes: ["/"] }, }, hooks: { async 'prerender:routes'(ctx) { // Fetch all blog posts const posts = await fetch("https://my-cms.com/posts").then(res => res.json()); // Pre-render each individual post for (const post of posts) { ctx.routes.add(`/blog/${post.slug}`); } // Pre-render category pages const categories = [...new Set(posts.map(post => post.category))]; for (const category of categories) { ctx.routes.add(`/category/${category}`); } // Pre-render tag pages (with pagination) const tags = [...new Set(posts.flatMap(post => post.tags))]; for (const tag of tags) { ctx.routes.add(`/tag/${tag}`); // Handle pagination for tags with many posts const tagPostCount = posts.filter(p => p.tags.includes(tag)).length; const pages = Math.ceil(tagPostCount / 10); for (let i = 2; i <= pages; i++) { ctx.routes.add(`/tag/${tag}/page/${i}`); } } } } });
Pre-rendering dynamic routes in Nuxt 3 with Nitro gives you the best of both worlds: the development experience of a dynamic application with the performance benefits of static HTML.
Sources:
- https://nuxt.com/docs/getting-started/prerendering,
- https://nuxt.com/docs/api/utils/prerender-routes,
- https://www.docs4.dev/posts/nuxt-3-hybrid-rendering-pre-render-dynamic-routes-ssg,
- https://github.com/codepie-io/nuxt3-dynamic-routes,
- https://nuxt.com/docs/guide/concepts/rendering,
- https://github.com/nuxt/nuxt/issues/30926,
- https://github.com/nuxt/nuxt/discussions/22006,
- https://masteringnuxt.com/blog/dynamic-pages-in-nuxt-3,
- https://www.youtube.com/watch?v=dtpKrqvwUTU,
Top comments (0)