← Volver al blog
EngineeringBuild in PublicSEO

Nuestras paginas Next.js pesaban demasiado para Bing. El payload RSC era el 58 % del HTML

Tres paginas Next.js atascadas en descubierta pero no rastreada en Bing. El App Router envia cada byte dos veces. Recortamos una en 48 KB y Bing la indexo.

8 de octubre de 2026

Nuestras paginas Next.js pesaban demasiado para Bing. El payload RSC era el 58 % del HTML

Katto es una herramienta de clipping de vídeo con IA. Le das un vídeo largo, encuentra los mejores momentos y los corta en clips verticales subtitulados. Lo construyo yo solo, en público, con Next.js y el App Router. Esta es una medición que cambió mi forma de escribir páginas, una cifra que di por buena delante de todo el mundo y resultó falsa, y una hipótesis mía que valía 108 bytes.

El síntoma

Bing Webmaster Tools mostraba varias de nuestras páginas como descubiertas pero nunca rastreadas. Ni bloqueadas por robots.txt, ni en noindex, ni lentas, ni redirigidas. Descubiertas y luego abandonadas. Google las tenía indexadas. Nuestro sitemap las listaba. Devolvían 200 a quien las pidiera.

Las páginas que rechazaba tenían una cosa en común, y no era su contenido.

El límite, y lo poco que sabemos de él

Microsoft no publica ningún tamaño a partir del cual su rastreador se rinde. Lo que tenemos son nuestras propias páginas, cada una con su estado leído en Bing Webmaster Tools y su peso servido medido el mismo día, sin comprimir, con el agente de bingbot:

Una sola página al otro lado de una línea no es una ley. Pero hay en esa lista una observación que vale más que todo el resto, porque es la misma URL dos veces. /compare/ai-video-clippers servía 172 295 bytes y llevaba semanas atascada en descubierta pero no rastreada. La recortamos a unos 124 KB. Hoy está indexada, con 127 951 bytes. Misma URL, misma plantilla, mismo tipo de contenido: demasiado grande, y luego lo bastante pequeña.

Hace una semana te habría dado otra cifra, y habría sido falsa. Tenía tres lecturas de estado y un hueco llamativo en la distribución de nuestros tamaños, y leí ahí un límite cercano a 125 KB. Dos de esas páginas han sido indexadas desde entonces con algo menos de 128 KB. Lo que nuestro propio sitio puede afirmar de verdad es que la línea está entre 128 y 140 KB, y que su otro lado sigue teniendo exactamente una página de ancho.

Si venías buscando una cifra, la respuesta honesta es que midas la tuya. La afirmación que sí puedo defender es más estrecha y más útil de todos modos: una página estancada en descubierta merece que la peses antes de que la reescribas, y una página que empieza a rastrearse después de adelgazar es la única prueba que cuenta de verdad.

Pesar el fichero fuente no te dice nada

Aquí está la parte específica de los React Server Components. El App Router serializa el árbol renderizado dentro del mismo documento HTML, como una serie de etiquetas self.__next_f.push(...), para que una navegación en cliente pueda continuar sin otra ida y vuelta. Ese payload no es una petición aparte que un rastreador pueda saltarse. Está en el documento.

Medido en una de nuestras páginas: 125 981 bytes servidos, de los cuales 73 571 son ese payload. El cincuenta y ocho por ciento del documento es la copia serializada de lo que el cuarenta y dos por ciento restante ya dice.

Así que una clase utilitaria escrita una sola vez dentro de un bucle de 24 filas no se envía 24 veces. Se envía 48.

Lo que más tardé en ver

No duplica la página. Duplica cada representación que la página ya lleva.

Nuestra roadmap renderizaba a propósito cada entrada dos veces: una como texto visible y otra dentro de un bloque ItemList de JSON-LD, para que los lectores máquina recibieran el nombre, la fecha y el estado como datos y no como prosa a interpretar. Razonable. Luego conté las apariciones de la descripción de una sola entrada en el documento servido y encontré cuatro.

Dos representaciones, cada una duplicada. Cuatro copias de la misma frase, y nunca se me había ocurrido contarlas.

El arreglo no era comprimir. El JSON-LD llevaba una description que copiaba palabra por palabra un texto que el lector ve treinta líneas más abajo, en el mismo idioma. No aportaba nada y costaba dos de las cuatro copias. Al quitarla, el bloque conserva el nombre, la fecha y el estado, que es justo lo que la prosa no le dice explícitamente a una máquina. Esa página pasó de 121 196 a 115 350 bytes sin que saliera ninguna información. Ambas cifras vienen del mismo build, antes y después de ese único cambio, que es la única forma de que un antes y un después signifiquen algo.

Si te llevas un solo hábito de aquí: antes de intentar aligerar nada, cuenta cuántas veces aparece una frase de tu contenido en el documento servido. Responde a una pregunta que pesar las secciones no responde.

Las dos palancas más grandes

Los atributos de clase repetidos, convertidos en reglas de hoja de estilo. Las utilidades de Tailwind son maravillosamente baratas de escribir, y viajan en cada elemento, dos veces. Mover las más repetidas a reglas @apply llevó nuestro índice de precios de 172 295 bytes a unos 142 000. Eran alrededor del 51 por ciento del marcado.

Los bloques no interactivos, fuera del árbol serializado. Para ser preciso, porque importa: son Server Components, así que nunca se hidratan en el cliente. El coste no es la hidratación, es la serialización. Cada elemento, cada prop y cada clave se escribe en el flujo para que una navegación en cliente pueda reconstruir el árbol sin ida y vuelta. Una tabla estática sin ningún comportamiento de cliente paga eso igualmente, y cuando la restricción es el tamaño del documento no hay razón para que siga siendo elementos de React. Ahora construimos esos bloques como una cadena HTML a partir de los mismos datos y la colocamos con dangerouslySetInnerHTML, escapando cada valor interpolado en el momento de construirla para que el escapado no dependa de dónde venga el dato. Otros 18 KB en el índice de precios. Una lista de 54 filas en la roadmap pasó de 157 308 a 119 031 por el mismo camino.

Lo que no funcionó

Antes de todo eso, estaba convencido de que el problema eran las fronteras de componente. Cincuenta y cuatro componentes next/link en una lista, cada uno aportando su nombre serializado, sus props y sus claves al payload. Sustituí los 54 por anclas simples.

Ahorró 108 bytes de 157 200.

Link es barato. El contenido que envuelve no lo es. Habría dedicado un día a reescribir componentes con esa teoría si no hubiera medido antes y después, y ese resultado negativo fue la cifra más útil del día.

Hay un suelo, y no es bajo

Nuestra página real más ligera, /contact, sirve 46 111 bytes llevando solo un título, un formulario corto y unas cuantas preguntas. El resto es navegación, pie de página, analítica y fuentes. Por debajo de esa cifra ya no hay nada que ganar página a página: sería un proyecto de armazón, no de página. Conocer el suelo te dice cuándo parar.

Una traducción cuesta bytes, no palabras

Pusimos esa roadmap en diez idiomas. Mismo marcado, misma estructura, misma información. La página inglesa sirve 116 239 bytes, la francesa 119 838, la japonesa 122 155 y la hindi 135 379.

El devanagari ocupa tres bytes por carácter en UTF-8 donde el texto latino ocupa uno, y el payload lo paga una segunda vez. Ninguna técnica a nivel de página toca eso: mismo marcado, misma información, diecinueve kilobytes de diferencia.

La página hindi es la interesante, porque con 135 379 bytes cae justo dentro de la banda que no sabemos resolver. Saber si Bing la procesa es el experimento más barato del que disponemos, y cuesta una inspección de URL.

Había escrito aquí un párrafo defendiendo que ese exceso no importaba mucho, porque cae al final del documento y el final de esa página es una lista cuyos títulos siguen en inglés de todas formas. Lo corté, porque da por hecho que el rastreador lee hasta agotar su presupuesto y entonces para. Todo lo que he observado de verdad solo dice que las páginas por encima de cierto tamaño no se procesan. Si el documento se rechaza entero, su orden no compra nada, y no tengo pruebas en ningún sentido. Es una teoría cómoda sobre mi propia página, que es justo el tipo que más conviene borrar.

Es un presupuesto, no un arreglo

El índice de precios que llevé de 172 295 a 124 202 bytes está hoy en 127 951, porque seguimos añadiéndole cosas: más herramientas, más columnas, diez traducciones. Sigue indexado, que es justo lo importante, y también ha vuelto a quedar a pocos kilobytes de la línea. No salió nada mal. Simplemente volvimos a gastar el presupuesto sin vigilarlo.

Esa es la conclusión real. En un framework que serializa su propia salida, el peso de una página no es una limpieza que se hace una vez. Es un número que sube cada vez que alguien hace un buen trabajo, y la única defensa es medir el documento servido en lugar del fuente, un cambio cada vez.

Cómo medir las tuyas

Artículos relacionados

¿Listo para convertir tus vídeos en clips virales?

Katto recorta, subtitula y reencuadra automáticamente tus vídeos largos en contenido de formato corto.

Prueba Katto gratis →