Mejores prácticas de rendimiento
Resumen condensado de las 25 mejores prácticas más importantes extraídas de todas las páginas de esta sección.
Busca en todas las páginas de la documentación
Resumen condensado de las 25 mejores prácticas más importantes extraídas de todas las páginas de esta sección.
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥
ANALYZE=true; recuerda que el mapa de árbol muestra bytes sin comprimir, así que verifica el tamaño de transferencia gzip/brotli en el panel de Red antes de celebrar victorias.index.ts con export * silenciosamente anulan tree-shaking incluso en módulos ES a menos que establescas "sideEffects": false en package.json; prefiere importaciones profundas o marca paquetes sin efectos secundarios para que el bundler pueda podar código no utilizado.LCP < 2.5s, INP < 200ms, CLS < 0.1) con una compilación de producción.Suspense con su propio Server Component asincrónico obtiene datos en paralelo automáticamente, así que dividir hermanos en límites separados te da paralelismo sin escribir Promise.all - un límite de nivel superior lo colapsa de nuevo en una cascada..map(async row => prisma.x.findUnique(...)) emite una consulta por fila; colapsa a un único JOIN mediante include/select y prefiere Promise.allSettled cuando un rechazo parcial no debería descartar todos los demás resultados.sizes con next/image: Sin sizes, el navegador asume 100vw y descarga la variante srcset más grande (a menudo 3840px) para una miniatura; pasa una cadena consciente de puntos de quiebre que coincida con tu layout y añade priority solo a la imagen de LCP para que el ancho de banda se gaste donde importa.<link> de Google Fonts con next/font/google (o next/font/local) para que las fuentes se envíen desde el mismo origen con encabezados de caché inmutable y métricas de fallback generadas automáticamente que eliminen FOUT y CLS; las fuentes variables ahorran alrededor de 100 KB en comparación con cargar múltiples archivos de peso.useMemo, useCallback y React.memo solo después de que el profiler muestre un costo real; memoizar prematuramente componentes económicos añade sobrecarga de comparación que frecuentemente supera el trabajo que ahorra.children (u un prop de objeto/función en línea) reconstruye ese valor en cada renderizado del padre, así que React.memo nunca ataja - ya sea eleva los children, usa el patrón de wrapper de estado children, o acepta que memo no ayudará allí.useEffect que inicie una búsqueda, añada un listener, establezca un temporizador, abra un WebSocket o inicialice una biblioteca de gráficos debe devolver una limpieza; el double-mount del Modo Estricto expone la limpieza que falta en lugar de causarla, e intervals/listeners filtrados retienen todo el estado del componente a través del cierre.AbortController y llama a abort() en la limpieza, así que cambios de dependencia o desmontajes no dejan respuestas obsoletas sobrescribiendo estado más nuevo o bloqueando GC de grandes payloads JSON.cookies()/headers() o cache: "no-store" desactiva Full Route Cache para toda la ruta, así que aísla ese código en su propio hijo Suspense.unstable_cache(fn, keyParts, { tags, revalidate }) con partes clave únicas y descriptivas, y recuerda que revalidatePath("/x") no toca rutas secundarias a menos que pases "layout".numberOfRuns: 3) y compara la mediana; establece umbrales de CI más bajos que tus números de producción locales para evitar fallos inestables.NODE_ENV=production, usa react-dom/profiling, cierra la pestaña Components durante la grabación, y compara actualDuration vs baseDuration para ver si la memoización realmente está pagando.children a un wrapper que posea el estado; los children se crean en el ámbito del padre, así que el wrapper con estado puede re-renderizarse sin re-renderizar el árbol estático - no se necesita memo.useSyncExternalStore para que los suscriptores de grano fino solo se re-rendericen cuando su slice específico cambie.experimental.reactCompiler: true (más babel-plugin-react-compiler) inserta memoización más granular que useMemo/useCallback/memo escritos a mano - adopta el compilador antes de arrancar memoización manual para que nunca dejes una brecha donde nada esté memoizado.Date.now()/Math.random() durante el renderizado o lecturas desde globales mutables o dejan de dispararse o cachean valores obsoletos - usa useSyncExternalStore para fuentes externas mutables."use client" en un layout contamina todo el subárbol y añade 100+ KB de JS de hidratación; mantén la directiva en la hoja interactiva más pequeña y pasa Server Components a través de children en wrappers de Client Component como <ThemeProvider>.fs, prisma u otros módulos solo de servidor dentro de un archivo "use client".useStore(s => s) se suscribe a la tienda completa, y useStore(s => ({ a: s.a, b: s.b })) crea un objeto fresco en cada actualización causando re-renderizados espurios; envuelve en useShallow desde zustand/react/shallow para comparar propiedades en lugar de identidad.performance.hints: "error", size-limit o la salida analyze de Next.js comparada con main) para que las regresiones causen fallo en la compilación en lugar de enviarse silenciosamente; empareja eso con una verificación de Lighthouse CI para que tanto bytes como métricas percibidas por el usuario cierren fusiones.Revisado por Chris St. John·Última actualización: 16 jul 2026
🤖 Read the SystemsArchitect.io Blog for over 100+ cloud architecture articles 🔥