⚡ Guía de Optimización de Rendimiento y SEO en Next.js
Esta guía recopila las estrategias clave y mejores prácticas para optimizar tus aplicaciones Next.js, logrando puntuaciones de 100/100 en Google Lighthouse (Core Web Vitals) y maximizando la visibilidad de tu sitio web en los motores de búsqueda (SEO).
🚀 1. Optimización de Rendimiento (Performance)
El rendimiento técnico de tu sitio es un factor de ranking crítico para Google. A continuación, se detallan las técnicas clave en Next.js:
A. Optimización de Imágenes (next/image)
Nunca uses la etiqueta nativa <img> en Next.js. El componente Image realiza optimizaciones automáticamente en el servidor:
- Conversión de Formato: Transforma imágenes pesadas (PNG/JPEG) a formatos modernos ultraligeros como WebP o AVIF de manera dinámica.
- Lazy Loading automático: Solo descarga las imágenes cuando están cerca del área visible del navegador (Viewport).
- Prevención de Cumulative Layout Shift (CLS): Requiere dimensiones (
widthyheight) o la propiedadfillpara reservar el espacio y evitar saltos visuales durante la carga.
import Image from "next/image";
export default function Avatar() {
return (
<Image
src="/user-profile.jpg"
alt="Foto de perfil del usuario"
width={120}
height={120}
className="rounded-full"
priority // Úsalo únicamente para la primera imagen visible (Above the Fold)
/>
);
}
B. Optimización de Fuentes (next/font)
Las fuentes autohospedadas previenen llamadas externas de red. Next.js descarga las fuentes de Google Fonts en tiempo de compilación y las sirve localmente junto a tus assets estáticos:
// src/app/layout.tsx
import { Inter } from "next/font/google";
const inter = Inter({
subsets: ["latin"],
display: "swap", // Evita que el texto sea invisible mientras se carga la fuente
variable: "--font-sans",
});
export default function RootLayout({ children }) {
return (
<html lang="es" className={inter.variable}>
<body>{children}</body>
</html>
);
}
C. Server Components vs. Client Components
Por defecto, en el App Router todos los componentes son Server Components (RSC). Esto es ideal porque:
- Cero peso de JavaScript es enviado al cliente por esos componentes.
- El renderizado inicial es sumamente veloz.
Regla de Oro: Mantén los componentes en el servidor tanto como sea posible. Solo añade la directiva "use client" cuando requieras interacción (Hooks de estado como useState, efectos como useEffect, o eventos como onClick).
🔍 2. Optimización para Motores de Búsqueda (SEO)
Next.js facilita el SEO técnico mediante su API nativa de Metadatos.
A. Configuración de Metadatos Estáticos
Declara el objeto metadata en tus layouts o páginas para configurar etiquetas meta esenciales:
// src/app/page.tsx
import { Metadata } from "next";
export const metadata: Metadata = {
title: "Mi Portafolio Profesional | Nombre Completo",
description:
"Portafolio de Ingeniería de Software con experiencia en desarrollo web full-stack y arquitecturas en la nube.",
openGraph: {
title: "Nombre Completo | Portafolio Profesional",
description: "Proyectos destacados y guías de programación.",
images: [{ url: "/og-image.png" }],
},
};
B. Metadatos Dinámicos
Si el título de una página depende de datos obtenidos de una base de datos o API (como un post de un blog o una guía), utiliza generateMetadata:
// src/app/guias/[slug]/page.tsx
import { Metadata } from "next";
import { guidesData } from "@/data/guides";
export async function generateMetadata({ params }): Promise<Metadata> {
const { slug } = await params;
const guide = guidesData.find((g) => g.slug === slug);
return {
title: `${guide?.title} | Sección de Guías`,
description: guide?.description,
};
}
🤖 3. Archivos Técnicos Clave para SEO
Sitemap XML (sitemap.ts)
Un sitemap indica a los motores de búsqueda cuáles son las páginas activas de tu web. En Next.js, puedes generarlo de forma dinámica:
// src/app/sitemap.ts
import { MetadataRoute } from "next";
import { guidesData } from "@/data/guides";
export default function sitemap(): MetadataRoute.Sitemap {
const baseUrl = "https://miportafolio.com";
// Páginas estáticas principales
const staticPages = ["", "/proyectos", "/sobre-mi", "/guias"].map(
(route) => ({
url: `${baseUrl}${route}`,
lastModified: new Date(),
changeFrequency: "weekly" as const,
priority: route === "" ? 1.0 : 0.8,
}),
);
// Páginas dinámicas de guías
const dynamicGuides = guidesData.map((guide) => ({
url: `${baseUrl}/guias/${guide.slug}`,
lastModified: new Date(),
changeFrequency: "monthly" as const,
priority: 0.6,
}));
return [...staticPages, ...dynamicGuides];
}
Robots.txt (robots.ts)
Indica a los rastreadores de búsqueda (crawlers) a dónde pueden acceder dentro de tu web:
// src/app/robots.ts
import { MetadataRoute } from "next";
export default function robots(): MetadataRoute.Robots {
return {
rules: {
userAgent: "*",
allow: "/",
disallow: "/private/",
},
sitemap: "https://miportafolio.com/sitemap.xml",
};
}