Web Design and Engineering

Core Web Vitals en Next.js en 2026: cómo llegar al verde

Pasos concretos para llegar a LCP bajo 2.5s, INP bajo 200ms y CLS bajo 0.1 en un SaaS Next.js 16, y cómo leer el campo cuando Lighthouse miente.

1 de junio de 20268 min de lectura
analog speedometer

Al final de esta guía tienes un SaaS Next.js 16 que pasa los Core Web Vitals en el percentil 75 de los datos reales: LCP por debajo de 2.5 segundos, INP por debajo de 200 milisegundos, CLS por debajo de 0.1. No una puntuación de Lighthouse en una pestaña. Usuarios de verdad sobre redes de verdad, medidos por Chrome User Experience Report en los últimos 28 días.

La búsqueda "core web vitals nextjs guide" devuelve un montón de checklists genéricas. Esta es específica de un SaaS Next.js 16 enviado en 2026, con el React Compiler estable, el Partial Prerendering listo para producción e INP como métrica de portada que la mayoría de los equipos sigue fallando.

Qué significa "verde" en Core Web Vitals en 2026

Tres métricas, cada una con su umbral en el percentil 75 que Google considera Bueno:

  • LCP (Largest Contentful Paint): bajo 2.5 segundos. Cuándo termina de pintarse el elemento más grande por encima del pliegue.
  • INP (Interaction to Next Paint): bajo 200 milisegundos. Sustituyó a FID el 12 de marzo de 2024. Mide la peor latencia end to end entre todas las interacciones del usuario en la página.
  • CLS (Cumulative Layout Shift): bajo 0.1. Desplazamiento de layout inesperado a lo largo del ciclo de vida de la página.

Los umbrales se aplican en el percentil 75 de los usuarios reales de Chrome de los últimos 28 días, segmentados por clase de dispositivo. Una página pasa solo si las tres métricas dan en Bueno. INP es la métrica que más sitios siguen sin pasar en 2026: en móvil, INP marca de media un 35.5% peor que FID en las comparaciones publicadas por Google antes de la migración, sacando a la luz interacciones que FID ignoraba en silencio.

El error más caro que vemos en los arranques: dar por hecho que un Lighthouse de 95 significa que el sitio está en verde. Lighthouse es dato de laboratorio. Google rankea con datos de campo de CrUX. Los dos divergen en redes reales, en dispositivos reales y en la cola larga de interacciones que Lighthouse no simula.

Qué necesitas antes de empezar

  • Un SaaS Next.js 16 en producción (App Router, React 19).
  • Acceso a PageSpeed Insights y Google Search Console del dominio.
  • Un destino de Real User Monitoring (RUM). Nosotros usamos un endpoint self-hosted que recibe el payload de web-vitals, pero cualquier herramienta de analítica que acepte eventos personalizados sirve.
  • Permiso para desplegar. Las correcciones de abajo viven en tu código, no en un ajuste de CDN.

Paso 1: Instrumenta con useReportWebVitals

No puedes arreglar lo que no mides en producción. Lighthouse es la versión laboratorio de la pregunta. CrUX es la versión pública. Tu RUM es la privada, y la única que saca a la superficie los problemas lo bastante rápido como para actuar sobre ellos.

Añade un client component que conecte useReportWebVitals de next/web-vitals y envíe cada métrica a tu endpoint:

'use client'
import { useReportWebVitals } from 'next/web-vitals'

export function WebVitals() {
  useReportWebVitals((metric) => {
    fetch('/api/vitals', {
      method: 'POST',
      body: JSON.stringify(metric),
      keepalive: true,
    })
  })
  return null
}

Renderízalo una vez en app/layout.tsx. El hook se dispara con cada Core Web Vital más FCP y TTFB. Agrupa el payload por ruta, por clase de dispositivo y por versión del deploy: así, cuando una métrica empeora, sabes qué commit ha enviado la regresión.

Paso 2: Arregla LCP con preload de imagen y dimensiones reservadas

En un SaaS Next.js, el LCP es casi siempre una imagen de una landing, y casi siempre un hero. Cuatro movimientos hacen la mayor parte del trabajo:

  1. Pon preload={true} en la imagen LCP. Next.js 16 ha deprecado la prop priority a favor de preload para que el comportamiento sea claro. El componente emite un <link rel="preload"> con fetchpriority="high" y en nuestras mediciones recorta entre 300 y 800 milisegundos de LCP. Úsalo en exactamente una imagen por página: la candidata a LCP.
  2. Pon width y height explícitos (o fill dentro de un padre con aspect ratio explícita). El componente reserva el espacio vía CSS aspect-ratio y elimina el layout shift que de otra forma destruiría el CLS.
  3. Inlínea el CSS crítico. Next.js 16 ya inliniza el CSS crítico por ruta por defecto. La trampa son los imports CSS globales que bloquean el render: peina app/layout.tsx y separa todo lo que no haga falta por encima del pliegue.
  4. Self-hostea las fuentes con display: swap y size-adjust. next/font se encarga de las dos cosas. El descriptor size-adjust sobre la métrica fallback impide que el swap del web font genere CLS cuando se carga.

Resiste la tentación de hacer preload de todo. Sobre-precargar añade entre 400 y 1200 milisegundos de retraso, porque el navegador se atasca en recursos que no están en el camino crítico. Un hero, no cinco.

Paso 3: Arregla INP con React Compiler, RSC y tareas troceadas

INP mide la peor latencia de interacción, end to end: input delay, runtime del event handler y el paint que viene después. Una página con un click lento de cada cien interacciones puede no pasar INP. Las soluciones son arquitectónicas, no cosméticas:

  • Activa el React Compiler. Estable en Next.js 16, lo activas con experimental.reactCompiler: true en next.config.ts. Memoriza componentes en automático y quita una clase de re-renders redundantes sin llamadas manuales a useMemo ni a memo(). La ganancia es constante: cada interacción hace menos trabajo, lo que comprime la cola larga que INP premia.
  • Mueve trabajo de cliente a Server Components. Los equipos que adoptan RSC del todo reportan reducciones del 50 al 70 por ciento en el JavaScript de primera carga. Menos JavaScript de cliente significa menos parse, menos hydration, menos contención en el main thread durante las interacciones.
  • Trocea las tareas largas. Cualquier handler que haga más de 50 ms de trabajo bloquea el siguiente paint. Cede el control con scheduler.yield() cuando esté disponible, si no con await new Promise(requestAnimationFrame). Saca el trabajo fuera del path del click metiéndolo en startTransition cuando no tenga que bloquear la respuesta visual.
  • Peina los event handlers. El panel Performance de Chrome DevTools marca las interacciones lentas en trazas equivalentes al campo. La guía de web.dev sobre cómo encontrar interacciones lentas en el campo es la referencia.

El trade-off honesto: el React Compiler puede sobre-memoizar de vez en cuando, manteniendo valores en memoria más tiempo del que pretendía tu código. Perfila después de activarlo. Los casos en los que empeora son raros e identificables.

Paso 4: Arregla CLS con dimensiones explícitas y disciplina en los fallback de PPR

El CLS parece fácil y no lo es. Las victorias rápidas:

  • Cada imagen, vídeo, iframe y slot publicitario lleva width y height explícitos, o un padre con aspect-ratio. Sin excepciones.
  • Reserva espacio para el contenido renderizado por el cliente. Skeleton loaders con las dimensiones del contenido final. Si la card final es 320x180, el skeleton es 320x180.
  • Fallbacks de fuente calibrados con size-adjust. El setup por defecto de next/font ya lo hace, pero los setups de fuente custom suelen regresar.

La trampa de 2026: el Partial Prerendering, estable en Next.js 16, introduce un nuevo riesgo de CLS. Cuando un fallback de Suspense dentro de un shell PPR se reemplaza por el contenido real, si las dimensiones difieren, la página se desplaza. Es peor que un shift de SSR completo porque el usuario ya ha visto un layout final. El arreglo: cada fallback de Suspense tiene las mismas dimensiones que el contenido que reemplaza.

Paso 5: Verifica en los datos de campo CrUX, no en Lighthouse

Manda las correcciones. Espera 28 días. Después mira CrUX.

PageSpeed Insights enseña campo y laboratorio uno al lado del otro. La sección de campo es la que cuenta para ranking y la que representa a tus usuarios. La sección de laboratorio sirve para debugging. Si el campo está en rojo y el laboratorio en verde, la brecha está en una red más lenta, un dispositivo más lento o una interacción de cola que no estás probando.

Para feedback más rápido que la ventana CrUX de 28 días: tu RUM. Configura un alert cuando el INP p75 de los últimos 7 días móviles cruce los 200 ms en una ruta de tráfico alto. Te da 21 días de ventaja sobre el momento en que Google lo notaría.

Errores comunes y cómo arreglarlos

  • Lighthouse en verde, CrUX en rojo. Tu máquina de prueba es demasiado rápida. Estrangula a Slow 4G más 4x CPU en DevTools y vuelve a tirar. Prueba en un Android de gama media de verdad, no solo en tu portátil.
  • LCP verde en desktop, rojo en móvil. Típico. El móvil descarga el mismo payload sobre una red peor. Audita el peso de las imágenes, las fuentes y cualquier script de terceros que bloquee el render.
  • INP subió después de activar el React Compiler. Algo en tu árbol re-renderiza más, no menos. Perfila con React DevTools y encuentra la prop o el contexto inestable que rompe la memoización.
  • CLS se dispara después de un rollout PPR. Uno de tus fallback de Suspense no tiene las mismas dimensiones que el contenido real. Diff layout por layout entre fallback y contenido final.

Para seguir

El verde en Core Web Vitals sobre Next.js 16 es el suelo, no el techo. Una lectura vecina vale tu tiempo cuando el suelo está hecho: nuestro análisis de qué cambia en Next.js 16 y React 19 para los nuevos proyectos SaaS.

Foto de Ryan Stone en Unsplash

Preguntas frecuentes

¿Cuánto tarda arreglar los Core Web Vitals en un SaaS Next.js?
De una a cuatro semanas de trabajo enfocado para un SaaS pequeño, más si tienes muchas páginas marketing con hero media pesados y una cola larga de interactividad de cliente. La instrumentación del Paso 1 lleva un día. Los arreglos de LCP y CLS suelen ser de dos a cinco días. El trabajo sobre INP es el abierto, porque depende de cuánto JavaScript de cliente envías hoy. Los datos de campo confirman el resultado 28 días tras el deploy.
¿Un Lighthouse en verde significa que paso los Core Web Vitals?
No. Lighthouse corre en un entorno controlado con dispositivo y red sintéticos. Google rankea con los datos del Chrome User Experience Report, que agrega usuarios reales sobre los últimos 28 días en el percentil 75. Un Lighthouse 95 con CrUX en rojo es lo habitual cuando tus usuarios reales están en redes más lentas, dispositivos más viejos o patrones de interacción que Lighthouse no simula.
¿Es seguro activar el React Compiler en producción en un SaaS Next.js 16?
Es estable desde Next.js 16. La mayoría de componentes se benefician de la memoización automática sin cambios en el código. Los casos límite donde empeora son componentes con closures anidadas inestables o librerías de terceros que mutan referencias en cada render. Actívalo, perfila durante una semana una muestra de rutas con muchas interacciones y vigila INP. Si una ruta regresa, quita el flag, documenta el caso y corrige el patrón origen.
¿Los Server Components mejoran INP de forma directa?
De forma indirecta. Los Server Components se renderizan en el servidor y stream el HTML, así que el navegador parsea, hidrata y ejecuta menos JavaScript. Menos trabajo de cliente significa más espacio en el main thread cuando el usuario interactúa. Los killers directos de INP son los event handlers lentos y las tareas largas durante la carga. Los Server Components quitan parte de las segundas pero no arreglan un click handler de 300 ms.

Studio

Empieza un proyecto.

Un partner único para el producto digital que necesitas construir. Producción más rápida, tecnología moderna, costes reducidos. Un equipo, una factura.