Presupuestos de rendimiento: definirlos y aplicarlos
Cómo definir, medir y aplicar presupuestos de rendimiento que evitan que tu aplicación web se degrade silenciosamente con el tiempo.

Toda aplicación web empieza siendo rápida. Luego alguien añade una librería de carrusel. Luego, un script de analítica. Luego, un selector de fechas que arrastra todo Moment.js. Seis meses después, tu landing page tarda 8 segundos en cargar y nadie puede señalar un solo commit responsable.
Los presupuestos de rendimiento existen para hacer visible y evitable este deterioro progresivo. Son cifras concretas — tamaño máximo del bundle, valor máximo de Time to Interactive, número máximo de peticiones — que tu proceso de build aplica automáticamente.
Qué incluir en el presupuesto
Los presupuestos de rendimiento se dividen en tres categorías: métricas de tiempo, métricas de tamaño y métricas de conteo. Cada una detecta un tipo distinto de regresión.
# performance-budget.yml
timing:
first-contentful-paint: 1800 # ms
largest-contentful-paint: 2500 # ms
time-to-interactive: 3500 # ms
cumulative-layout-shift: 0.1 # unitless
size:
total-bundle: 250 # KB (compressed)
javascript: 170 # KB (compressed)
css: 50 # KB (compressed)
images-per-page: 500 # KB
count:
requests: 50
third-party-scripts: 3Empieza por las métricas más relevantes para tu aplicación. Un sitio de e-commerce probablemente priorice Largest Contentful Paint (imágenes de producto). Un dashboard probablemente priorice Time to Interactive (JavaScript complejo). Un sitio de contenido probablemente priorice First Contentful Paint (renderizado de texto).
Medir el cumplimiento del presupuesto
Lighthouse CI integra las comprobaciones de presupuesto de rendimiento directamente en tu pipeline de CI. Ejecuta Lighthouse contra tu aplicación desplegada o servida localmente y compara los resultados con los umbrales definidos.
// lighthouserc.js
module.exports = {
ci: {
collect: {
url: ['http://localhost:3000/', 'http://localhost:3000/dashboard'],
numberOfRuns: 3,
},
assert: {
assertions: {
'first-contentful-paint': ['warn', { maxNumericValue: 1800 }],
'largest-contentful-paint': ['error', { maxNumericValue: 2500 }],
'interactive': ['error', { maxNumericValue: 3500 }],
'cumulative-layout-shift': ['error', { maxNumericValue: 0.1 }],
'total-byte-weight': ['warn', { maxNumericValue: 500000 }],
},
},
upload: {
target: 'temporary-public-storage',
},
},
};La distinción entre warn y error importa. Los warnings señalan regresiones en los comentarios del pull request. Los errors bloquean el merge. Usa warnings para objetivos aspiracionales y errors para límites innegociables.
Monitoreo del tamaño del bundle
El tamaño del bundle es la métrica de rendimiento más predecible. A diferencia de las métricas de tiempo (que varían según el dispositivo y la red), el tamaño del bundle es determinista: mismo código, mismo tamaño, siempre.
// bundlesize.config.js — or use bundlewatch, size-limit
module.exports = [
{
path: 'dist/main.*.js',
maxSize: '120 KB',
compression: 'gzip',
},
{
path: 'dist/vendor.*.js',
maxSize: '80 KB',
compression: 'gzip',
},
{
path: 'dist/*.css',
maxSize: '30 KB',
compression: 'gzip',
},
];Herramientas como size-limit van más allá: miden no solo el tamaño del archivo sino también el tiempo de ejecución real y el costo de parseo:
# package.json
{
"size-limit": [
{
"path": "dist/index.js",
"limit": "15 KB",
"running": true
}
],
"scripts": {
"size": "size-limit",
"size:check": "size-limit --why"
}
}Ejecutar size-limit --why muestra exactamente qué dependencias contribuyen a tu bundle, que es como encuentras esa librería de 200 KB que alguien importó para una sola función utilitaria.
Análisis de bundles con Webpack
Cuando un presupuesto falla, necesitas entender por qué. Los analizadores de bundles visualizan qué hay dentro de tus bundles.
// webpack.config.js
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
module.exports = {
plugins: [
new BundleAnalyzerPlugin({
analyzerMode: 'static',
reportFilename: 'bundle-report.html',
openAnalyzer: false,
}),
],
};Hallazgos comunes al analizar un bundle:
- Dependencias duplicadas: dos versiones de la misma librería (por ejemplo, lodash 4.x y 3.x) debido a dependencias transitivas
- Exports sin usar: importar una librería completa cuando solo usas una función — el tree shaking únicamente funciona con módulos ES
- Datos de configuración regional: librerías como Moment.js o date-fns incluyen todos los locales por defecto
// ❌ Imports entire lodash — 70KB+ in your bundle
import _ from 'lodash';
const result = _.groupBy(items, 'category');
// ✅ Cherry-pick the function — ~1KB
import groupBy from 'lodash/groupBy';
const result = groupBy(items, 'category');Presupuestos de rendimiento para imágenes
Las imágenes suelen representar entre el 50 % y el 70 % del peso de una página. Un presupuesto de imágenes evita que el patrón de "una imagen hero más" termine arruinando los tiempos de carga.
interface ImageBudget {
maxSizeKB: number;
maxDimensions: { width: number; height: number };
requiredFormats: string[];
}
const imageBudgets: Record<string, ImageBudget> = {
hero: {
maxSizeKB: 150,
maxDimensions: { width: 1920, height: 1080 },
requiredFormats: ['webp', 'avif'],
},
thumbnail: {
maxSizeKB: 30,
maxDimensions: { width: 400, height: 300 },
requiredFormats: ['webp'],
},
avatar: {
maxSizeKB: 15,
maxDimensions: { width: 200, height: 200 },
requiredFormats: ['webp'],
},
};Aplica los presupuestos de imágenes en tiempo de build mediante compresión automatizada. Rechaza las imágenes que superen el presupuesto antes de que lleguen a producción.
Aplicar los presupuestos en CI/CD
El presupuesto solo funciona si no se puede ignorar. Integra las comprobaciones en el flujo de trabajo del pull request para que las regresiones sean visibles antes del merge.
# .github/workflows/performance.yml
name: Performance Budget
on: [pull_request]
jobs:
budget-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
- run: npm ci
- run: npm run build
- name: Check bundle size
run: npx size-limit
- name: Lighthouse CI
run: |
npm install -g @lhci/cli
lhci autorunCuando un presupuesto se rompe: investiga antes de subir el límite. La mayoría de las regresiones tienen una solución más barata que aumentar el presupuesto — lazy loading, code splitting o reemplazar una dependencia sobredimensionada.
Conclusiones clave
- Define los presupuestos desde el principio — mantener el rendimiento es más fácil que recuperarlo
- Presupuesta primero el tamaño del bundle — es determinista y medible en CI sin necesidad de un servidor en ejecución
- Usa
errorpara límites estrictos ywarnpara objetivos — bloquea el merge solo por umbrales innegociables - Analiza antes de subir los límites — la mayoría de las regresiones tienen soluciones más pequeñas que aumentar el presupuesto
- Los presupuestos de imágenes tienen el mayor retorno — las imágenes son el mayor peso en la mayoría de las páginas
- Automatiza la aplicación en CI — un presupuesto que nadie revisa es un presupuesto que nadie respeta


