# Nuxt 3: SSR y generación estática, la guía completa > Domine el SSR y la generación estática con Nuxt 3. Desde useFetch hasta route rules, aprenda a optimizar el rendimiento de sus aplicaciones Vue.js. - Published: 2026-02-11 - Updated: 2026-04-28 - Author: SharpSkill - Tags: nuxt 3, vue.js, ssr, generación estática, rendimiento web - Reading time: 12 min --- Nuxt 3 transforma la manera en que se construyen las aplicaciones Vue.js al ofrecer múltiples modos de renderizado adaptados a diferentes casos de uso. Desde el Server-Side Rendering (SSR) hasta la generación estática y el renderizado híbrido, el framework brinda una flexibilidad notable para optimizar el rendimiento y el SEO. > **Requisitos previos** > > Este tutorial asume conocimientos básicos de Vue 3 y la Composition API. La familiaridad con los conceptos de renderizado del lado del servidor resulta útil pero no es obligatoria, ya que los fundamentos se explican a lo largo de la guía. ## Comprender los modos de renderizado de Nuxt 3 Antes de adentrarse en el código, resulta esencial entender las diferencias entre los modos de renderizado disponibles. Cada modo responde a necesidades específicas en términos de rendimiento, SEO y experiencia de usuario. El SSR (Server-Side Rendering) genera el HTML en el servidor para cada solicitud. La generación estática (SSG) pre-genera todas las páginas en el momento del build. El modo híbrido permite combinar ambos enfoques página por página. ```typescript // nuxt.config.ts // Configuración de los diferentes modos de renderizado export default defineNuxtConfig({ // SSR activado por defecto (recomendado para SEO) ssr: true, // Generación estática: pre-renderiza todas las páginas // Usar 'npm run generate' para construir // target: 'static', // Sintaxis Nuxt 2 // Modo híbrido: configurable por ruta routeRules: { // Página de inicio: pre-renderizada y cacheada '/': { prerender: true }, // Blog: generación estática '/blog/**': { prerender: true }, // Dashboard: renderizado solo en cliente '/dashboard/**': { ssr: false }, // API: sin pre-renderizado '/api/**': { prerender: false } } }) ``` Esta configuración demuestra el poder del modo híbrido: cada sección de la aplicación utiliza el modo de renderizado más adecuado a sus necesidades. ## Obtención de datos con useFetch y useAsyncData Nuxt 3 ofrece dos composables principales para obtener datos de forma isomorfa. Estos composables funcionan tanto en el servidor como en el cliente, con una gestión automática de la hidratación. `useFetch` es un wrapper alrededor de `useAsyncData` que simplifica las llamadas HTTP. `useAsyncData` ofrece más control para casos de uso avanzados. ```vue ``` Para los casos que requieren más control, `useAsyncData` permite ejecutar cualquier función asíncrona. ```vue ``` Estos composables evitan el doble fetching: los datos obtenidos en el servidor se serializan en el payload HTML y se reutilizan durante la hidratación del cliente. ## Personalizar el SSR con server hooks El SSR de Nuxt 3 puede personalizarse mediante server hooks. Estos hooks permiten intervenir en distintas etapas del ciclo de renderizado para modificar el comportamiento por defecto. ```typescript // server/plugins/render-hooks.ts // Plugin de servidor para personalizar el renderizado SSR export default defineNitroPlugin((nitroApp) => { // Hook ejecutado antes de renderizar cada página nitroApp.hooks.hook('render:html', (html, { event }) => { // Inyectar scripts o metadatos html.head.push(` `) }) // Hook para gestión del caché de renderizado nitroApp.hooks.hook('render:response', (response, { event }) => { // Añadir cabeceras de caché personalizadas const path = event.path if (path.startsWith('/blog/')) { // Caché largo para artículos del blog response.headers['Cache-Control'] = 'public, max-age=3600, s-maxage=86400' } else if (path.startsWith('/api/')) { // Sin caché para APIs response.headers['Cache-Control'] = 'no-store' } }) }) ``` > **Rendimiento del SSR** > > El hook `render:response` resulta ideal para implementar estrategias de caché HTTP. Combinar SSR con un CDN que respete las cabeceras Cache-Control permite servir páginas pre-renderizadas manteniendo la capacidad de invalidarlas. ## Generación estática con nuxt generate La generación estática pre-construye todas las páginas en el momento del build. Este enfoque resulta ideal para sitios con contenido estable como blogs, documentación o sitios de marketing. Para las rutas dinámicas, Nuxt necesita conocer todas las URLs a generar. El hook `prerender:routes` permite definir estas rutas de forma programática. ```typescript // nuxt.config.ts // Configuración completa para generación estática export default defineNuxtConfig({ // Activar generación estática nitro: { prerender: { // Activar el rastreo automático de enlaces crawlLinks: true, // Rutas que siempre deben incluirse routes: ['/', '/about', '/contact'], // Ignorar ciertas rutas ignore: ['/admin', '/api'] } }, hooks: { // Hook para generar rutas dinámicas async 'prerender:routes'(ctx) { // Obtener artículos desde API o BD const articles = await fetch('https://api.example.com/articles') .then(res => res.json()) // Añadir rutas de artículos for (const article of articles) { ctx.routes.add(`/blog/${article.slug}`) } // Obtener categorías const categories = await fetch('https://api.example.com/categories') .then(res => res.json()) for (const category of categories) { ctx.routes.add(`/category/${category.slug}`) } } } }) ``` Para proyectos con muchas páginas, el crawler automático puede resultar insuficiente. He aquí un enfoque más robusto con un archivo de configuración separado. ```typescript // server/utils/generate-routes.ts // Utilidad para generar la lista de rutas dinámicas import { prisma } from './prisma' export async function getAllStaticRoutes(): Promise { const routes: string[] = [] // Artículos del blog const articles = await prisma.article.findMany({ where: { published: true }, select: { slug: true, category: { select: { slug: true } } } }) for (const article of articles) { routes.push(`/blog/${article.category.slug}/${article.slug}`) } // Páginas de productos const products = await prisma.product.findMany({ where: { active: true }, select: { slug: true } }) for (const product of products) { routes.push(`/products/${product.slug}`) } // Páginas de etiquetas const tags = await prisma.tag.findMany({ select: { slug: true } }) for (const tag of tags) { routes.push(`/tags/${tag.slug}`) } return routes } ``` ## Renderizado híbrido con routeRules El renderizado híbrido es la característica estrella de Nuxt 3. Permite definir reglas de renderizado distintas por ruta, combinando lo mejor del SSR y del SSG. ```typescript // nuxt.config.ts // Configuración avanzada de renderizado híbrido export default defineNuxtConfig({ routeRules: { // Páginas de marketing: pre-renderizadas y cacheadas a largo plazo '/': { prerender: true }, '/pricing': { prerender: true }, '/features/**': { prerender: true }, // Blog: ISR (Incremental Static Regeneration) // Revalidación cada hora '/blog/**': { isr: 3600, prerender: true }, // Documentación: caché CDN con revalidación '/docs/**': { swr: 86400, // Stale-while-revalidate prerender: true }, // E-commerce: SSR con caché corto '/products/**': { ssr: true, cache: { maxAge: 60, staleMaxAge: 300 } }, // Carrito y checkout: solo en cliente '/cart': { ssr: false }, '/checkout/**': { ssr: false }, // Dashboard: modo SPA '/dashboard/**': { ssr: false, // Desactivar pre-renderizado prerender: false }, // Rutas API: sin caché por defecto '/api/**': { cors: true, headers: { 'Access-Control-Allow-Methods': 'GET,POST,PUT,DELETE' } } } }) ``` Esta configuración ilustra una arquitectura típica de aplicación moderna: las páginas públicas se optimizan para SEO con SSG, mientras que las secciones interactivas utilizan renderizado en el cliente. ## Optimización del rendimiento con caché de datos Más allá del caché de páginas, Nuxt 3 permite cachear los datos obtenidos. Esta estrategia reduce la carga sobre las APIs y mejora los tiempos de respuesta. ```typescript // server/api/articles/[slug].get.ts // Endpoint API con caché de datos import { getArticleBySlug } from '~/server/utils/articles' export default defineCachedEventHandler( async (event) => { const slug = getRouterParam(event, 'slug') if (!slug) { throw createError({ statusCode: 400, message: 'Slug ausente' }) } const article = await getArticleBySlug(slug) if (!article) { throw createError({ statusCode: 404, message: 'Artículo no encontrado' }) } return article }, { // Clave de caché basada en el slug getKey: (event) => `article-${getRouterParam(event, 'slug')}`, // Duración del caché: 1 hora maxAge: 3600, // Stale-while-revalidate: servir caché obsoleto durante la actualización staleMaxAge: 7200, // Invalidación basada en tags tags: ['articles'] } ) ``` Para invalidar el caché cuando cambia el contenido, Nuxt proporciona un sistema de tags. ```typescript // server/api/articles/[slug].put.ts // Actualización de artículo con invalidación de caché import { updateArticle } from '~/server/utils/articles' export default defineEventHandler(async (event) => { const slug = getRouterParam(event, 'slug') const body = await readBody(event) // Actualizar el artículo const article = await updateArticle(slug, body) // Invalidar el caché para este artículo await useStorage('cache').removeItem(`nitro:handlers:article-${slug}`) // O invalidación basada en tags (todos los artículos) // await useStorage('cache').clear('articles') return article }) ``` > **Caché distribuido** > > En producción con múltiples instancias, el caché en memoria resulta insuficiente. Se recomienda configurar Redis u otro sistema distribuido mediante la configuración de Nitro para garantizar la coherencia entre instancias. ## Gestión del SEO y metadatos El SSR permite optimizar el SEO al generar los metadatos en el servidor. Nuxt 3 ofrece varios enfoques para gestionar las meta tags de forma dinámica. ```vue ``` Para las páginas estáticas, los metadatos pueden definirse directamente en el componente. ```vue ``` ## Despliegue y consideraciones de producción La elección del despliegue depende del modo de renderizado utilizado. He aquí las principales opciones y sus configuraciones. ```typescript // nuxt.config.ts // Configuración para distintos entornos de despliegue export default defineNuxtConfig({ nitro: { // Preset según la plataforma objetivo // preset: 'vercel', // Vercel // preset: 'netlify', // Netlify // preset: 'cloudflare-pages', // Cloudflare // preset: 'node-server', // Node.js clásico // Configuración para Node.js en producción preset: 'node-server', // Compresión de respuestas compressPublicAssets: true, // Configuración del almacenamiento de caché storage: { cache: { driver: 'redis', url: process.env.REDIS_URL } } }, // Variables de entorno en runtime runtimeConfig: { // Secretos (no expuestos al cliente) apiSecret: process.env.API_SECRET, // Configuración pública public: { apiBase: process.env.NUXT_PUBLIC_API_BASE || '/api' } } }) ``` Para el despliegue estático, el comando `npm run generate` crea una carpeta `.output/public` lista para desplegar en cualquier host de archivos estáticos. ```bash # Generación estática npm run generate # El contenido de .output/public puede desplegarse en: # - Vercel (detección automática) # - Netlify (configuración automática) # - GitHub Pages # - S3 + CloudFront # - Cualquier CDN o servidor de archivos estáticos ``` ## Conclusión Nuxt 3 ofrece una flexibilidad excepcional para renderizar aplicaciones Vue.js. La elección entre SSR, SSG y renderizado híbrido depende de las necesidades específicas de cada proyecto. **Puntos clave:** ✅ **SSR**: ideal para contenido dinámico que requiere buen SEO (e-commerce, sitios de noticias) ✅ **SSG**: perfecto para contenido estable (blogs, documentación, sitios de marketing) ✅ **Híbrido**: el mejor enfoque para aplicaciones complejas con necesidades variadas ✅ **useFetch/useAsyncData**: hidratación automática y gestión de caché ✅ **routeRules**: configuración granular para el comportamiento de cada ruta ✅ **Caché**: múltiples estrategias para optimizar el rendimiento en producción Combinar el renderizado híbrido con una estrategia de caché bien pensada permite construir aplicaciones de alto rendimiento optimizadas para SEO, manteniendo la interactividad de las Single Page Applications. --- Source: SharpSkill (https://sharpskill.dev), tech interview preparation for your real stack. HTML version of this page: https://sharpskill.dev/es/blog/vue-nuxt/nuxt-3-ssr-static-generation