Saltar al contenido
devjose↗FRONTEND ENGINEER · LIMA, PE
TrabajoSobre míExperienciaBlogHablemos
Inicio/Blog

DESARROLLO FRONTEND

Next.js Performance en 2025: Guía Definitiva (con checklist)

Mejora Core Web Vitals en Next.js: imágenes, RSC, caché, code splitting y auditorías. Guía práctica con checklist.

Por José Manrique · 1 de setiembre de 2025

TL;DR
Optimiza imágenes con next/image (+sizes), usa Server Components por defecto, separa cliente con 'use client', activa caché/ISR, divide código crítico y mide con Lighthouse/Core Web Vitals.

🚀 Importante: Performance es un proceso iterativo. No trates de implementar todo de una vez.

0. Checklist rápido

  • ☑ next/image con sizes y priority solo above-the-fold
  • ☑ Fuentes con next/font (display: 'swap', preload: true en críticas)
  • ☐ Server Components by default; Client solo si hay estado/efectos
  • ☐ dynamic() + suspense para UX fluida
  • ☐ Caching: ISR/Route Segment Config (revalidate), Edge donde haga sentido
  • ☐ @next/bundle-analyzer para podar dependencias
  • ☐ Prefetch selectivo de enlaces críticos (<Link prefetch>)

1. Comparación de Métricas Core Web Vitals

MétricaSin OptimizarCon OptimizaciónMejora
LCP4.2s1.8s57%
FID280ms45ms84%
CLS0.250.0580%

Datos basados en testing real con Lighthouse

2. Image Optimization con next/image

Configuración básica

Incluye sizes para evitar servir imágenes sobredimensionadas y reducir CLS:

import Image from 'next/image'

export function OptimizedImage() {
  return (
    <Image
      src="/hero-image.jpg"
      alt="Hero con producto"
      width={1200}
      height={800}
      priority
      placeholder="blur"
      blurDataURL="data:image/jpeg;base64,..."
      sizes="(max-width: 768px) 100vw, 1200px"
    />
  )
}

Técnicas avanzadas

  1. Responsive images: Usa sizes correctamente
  2. Lazy loading: Por defecto en next/image
  3. WebP/AVIF: Automático con Next.js
  4. Placeholder blur: Mejora UX durante carga

3. Code Splitting y Lazy Loading

En app router, dynamic + suspense para componentes pesados:

import dynamic from 'next/dynamic'
import { Suspense } from 'react'

const Heavy = dynamic(() => import('../components/Heavy'), { 
  ssr: false,
  loading: () => <p>Cargando componente...</p>
})

export default function Page() {
  return (
    <Suspense fallback={<div className="animate-pulse">Cargando...</div>}>
      <Heavy />
    </Suspense>
  )
}

4. Optimización de Fuentes

Evita FOIT/FOUT con next/font y variable CSS:

import { Inter, Sora } from 'next/font/google'

export const inter = Inter({
  subsets: ['latin'],
  display: 'swap',
  variable: '--font-inter',
  preload: true
})

export const sora = Sora({
  subsets: ['latin'],
  display: 'swap',
  variable: '--font-sora'
})

Buenas prácticas para fuentes:

  • ✅ Usa font-display: swap
  • ✅ Preload solo fuentes críticas
  • ✅ Limita el número de font weights
  • ❌ No uses Google Fonts directo en CSS

5. Server vs Client Components

Regla de oro: Server por defecto, Client solo cuando necesites

// ✅ Server Component (por defecto)
export default async function Products() {
  const data = await getData() // se ejecuta en el server
  return <ProductList data={data} />
}

// ✅ Client Component (solo cuando necesites estado/eventos)
'use client'
import { useState } from 'react'

export function Counter() {
  const [count, setCount] = useState(0)
  
  return (
    <button 
      onClick={() => setCount(count + 1)}
      className="px-4 py-2 bg-blue-500 text-white rounded"
    >
      Clicks: {count}
    </button>
  )
}

6. Bundle Analysis y Tree Shaking

Instalar analyzer

npm install --save-dev @next/bundle-analyzer

Configurar next.config.js

const withBundleAnalyzer = require('@next/bundle-analyzer')({
  enabled: process.env.ANALYZE === 'true'
})

module.exports = withBundleAnalyzer({
  experimental: { 
    optimizePackageImports: ['lodash', 'date-fns', 'lucide-react'] 
  },
  images: {
    formats: ['image/avif', 'image/webp'],
    remotePatterns: [
      {
        protocol: 'https',
        hostname: '**',
      },
    ],
  }
})

7. Estrategias de Caché y ISR

Por página

// app/products/page.tsx
export const revalidate = 3600 // ISR cada hora

export default async function ProductsPage() {
  const products = await getProducts()
  return <ProductGrid products={products} />
}

Por request

// Para datos que cambian frecuentemente
export const dynamic = 'force-dynamic'
export const runtime = 'edge' // opcional: usar Edge Runtime

8. Monitoreo y Métricas

Web Vitals tracking

// app/layout.tsx
import { Analytics } from '@vercel/analytics/react'
import { SpeedInsights } from '@vercel/speed-insights/next'

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        {children}
        <Analytics />
        <SpeedInsights />
      </body>
    </html>
  )
}

Custom performance tracking

'use client'
import { getCLS, getFID, getFCP, getLCP, getTTFB } from 'web-vitals'

export function WebVitals() {
  useEffect(() => {
    getCLS(console.log)
    getFID(console.log)
    getFCP(console.log)
    getLCP(console.log)
    getTTFB(console.log)
  }, [])

  return null
}

Roadmap de Optimización

Fase 1: Fundamentos (Semana 1)

  • ☐ Configurar next/image en todas las imágenes
  • ☐ Implementar next/font para todas las fuentes
  • ☐ Auditoría inicial con Lighthouse

Fase 2: Arquitectura (Semana 2)

  • ☐ Separar Server/Client components
  • ☐ Implementar lazy loading en componentes pesados
  • ☐ Configurar ISR en páginas estáticas

Fase 3: Optimización avanzada (Semana 3)

  • ☐ Bundle analysis y tree shaking
  • ☐ Edge Runtime donde sea apropiado
  • ☐ Implementar monitoreo continuo

Conclusión

La performance no es un destino, es un viaje

Performance en Next.js es un proceso iterativo: mide → prioriza → implementa → valida.

Empieza siempre por:

  1. 🖼️ Imágenes (mayor impacto, menor esfuerzo)
  2. 🔤 Fuentes (mejora percepción de velocidad)
  3. 🗄️ Caché (reduce carga del servidor)
  4. 📦 Bundle (menos JavaScript = más velocidad)

¿Qué técnica vas a implementar primero? ¡Compárteme tus resultados!


Links útiles:

  • Next.js Performance Docs
  • Web Vitals
  • Bundle Analyzer

Sigue leyendo

Angular vs React en 2025: lo que nadie te cuenta (mi experiencia) ↗TypeScript Pro Tips: 10 técnicas para subir de nivel tu frontend ↗Todos los artículos
devjose↗

© 2026 José Manrique

BlogGitHub LinkedIn PrivacidadTérminosArriba ↑