# 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
Cargando artículo...
{{ article.title }}
```
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