Performance Budget Setter
Set and enforce performance budgets to maintain fast user experiences.
Performance Budget Template
Performance Budget: E-Commerce Website
Bundle Size Budget
| Asset Type | Budget | Current | Status |
|---|---|---|---|
| Initial JS | 200 KB | 185 KB | ✅ |
| Initial CSS | 50 KB | 48 KB | ✅ |
| Vendor JS | 150 KB | 145 KB | ✅ |
| Fonts | 100 KB | 95 KB | ✅ |
| Images (above fold) | 300 KB | 320 KB | ❌ |
| Total Initial Load | 800 KB | 793 KB | ✅ |
API Latency Budget
| Endpoint | p50 | p95 | p99 |
|---|---|---|---|
| GET /products | <100ms | <300ms | <500ms |
| POST /checkout | <200ms | <500ms | <1000ms |
| GET /search | <150ms | <400ms | <800ms |
Database Query Budget
| Query Type | Budget | Current |
|---|---|---|
| Simple reads | <50ms | 42ms |
| Complex joins | <200ms | 185ms |
| Aggregations | <500ms | 450ms |
| Queries per page | <20 | 18 |
Core Web Vitals
| Metric | Good | Poor | Target |
|---|---|---|---|
| LCP (Largest Contentful Paint) | <2.5s | >4.0s | <2.0s |
| FID (First Input Delay) | <100ms | >300ms | <50ms |
| CLS (Cumulative Layout Shift) | <0.1 | >0.25 | <0.05 |
Page-Specific Budgets
Homepage
- Time to Interactive: <3s
- Total Blocking Time: <300ms
- Speed Index: <3s
Product Page
- Time to Interactive: <4s
- Images loaded: <2s
- Reviews section: <1s
Checkout
- Time to Interactive: <3s
- Payment processing: <2s
- Zero layout shifts
Third-Party Scripts
| Service | Budget | Purpose |
|---|---|---|
| Analytics | 30 KB | Google Analytics |
| Chat Widget | 50 KB | Customer support |
| Payment | 100 KB | Stripe |
| Total | 180 KB |
Enforcement Strategy
- CI/CD Integration
.github/workflows/performance-budget.yml
name: Performance Budget Check
on: [pull_request]
jobs: budget-check: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2
- name: Build production bundle
run: npm run build
- name: Check bundle size
run: |
npx bundlesize
- name: Lighthouse CI
run: |
npm install -g @lhci/cli
lhci autorun
2. Webpack Bundle Analyzer
// webpack.config.js const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
module.exports = { plugins: [ new BundleAnalyzerPlugin({ analyzerMode: process.env.ANALYZE ? "server" : "disabled", }), ], performance: { hints: "error", maxAssetSize: 200000, // 200 KB maxEntrypointSize: 400000, // 400 KB }, };
- package.json Configuration
{ "bundlesize": [ { "path": "./dist/js/main..js", "maxSize": "200 KB" }, { "path": "./dist/css/main..css", "maxSize": "50 KB" }, { "path": "./dist/js/vendor.*.js", "maxSize": "150 KB" } ] }
Monitoring Plan
Real User Monitoring (RUM)
// Track Core Web Vitals import { getCLS, getFID, getFCP, getLCP, getTTFB } from "web-vitals";
function sendToAnalytics(metric) { const body = JSON.stringify(metric);
if (navigator.sendBeacon) { navigator.sendBeacon("/analytics", body); } else { fetch("/analytics", { body, method: "POST", keepalive: true }); } }
getCLS(sendToAnalytics); getFID(sendToAnalytics); getLCP(sendToAnalytics);
Synthetic Monitoring
Lighthouse CI
lhci autorun --config=.lighthouserc.json
WebPageTest API
curl "https://www.webpagetest.org/runtest.php?url=https://example.com&k=API_KEY"
Performance Dashboard
Daily Metrics:
- Bundle size trend
- API latency percentiles
- Core Web Vitals scores
- Page load times
Alerts:
- Bundle size exceeds budget by 10%
- LCP >2.5s for >5% of users
- API p95 >500ms
- Any metric exceeds budget
Optimization Strategies
Reduce Bundle Size
// Code splitting const ProductPage = lazy(() => import("./ProductPage"));
// Tree shaking import { specific } from "library"; // ✅ import * as library from "library"; // ❌
// Dynamic imports if (featureFlag) { const module = await import("./feature"); }
Optimize API Calls
// Parallel requests const [user, orders] = await Promise.all([fetchUser(id), fetchOrders(id)]);
// Caching const cachedData = await redis.get(key); if (cachedData) return cachedData;
// Pagination const products = await db.products .find() .limit(20) .skip((page - 1) * 20);
Optimize Database Queries
-- Add indexes CREATE INDEX idx_orders_user_created ON orders(user_id, created_at);
-- Limit columns SELECT id, name FROM products; -- ✅ SELECT * FROM products; -- ❌
-- Use EXPLAIN EXPLAIN ANALYZE SELECT ...;
Budget Violation Response
When Budget Exceeded
Immediate:
-
Block PR from merging
-
Notify team in Slack
-
Create ticket
Within 24 hours:
-
Investigate cause
-
Identify optimization opportunities
-
Propose fix or budget increase
Decision:
-
Fix code (preferred)
-
Increase budget (requires justification)
Budget Increase Request Template
Budget Increase Request
Component: Main JS bundle Current Budget: 200 KB Requested Budget: 250 KB Reason: Added critical feature X
Impact Analysis:
- Load time increase: +0.5s
- User impact: Medium
- Revenue impact: Unknown
Alternatives Considered:
- Code splitting: Reduces to 210 KB (preferred)
- Remove feature Y: Reduces to 195 KB (rejected)
- Lazy loading: Complex, 3 weeks effort
Recommendation: Implement code splitting
Best Practices
-
Set realistic budgets: Based on user data
-
Enforce in CI: Automated checks
-
Monitor continuously: RUM + synthetic
-
Review quarterly: Adjust as needed
-
Prioritize UX: User-centric metrics
-
Document exceptions: Why budget increased
-
Celebrate wins: When under budget
Output Checklist
-
Bundle size budgets defined
-
API latency targets set
-
Database query budgets
-
Core Web Vitals targets
-
Page-specific budgets
-
CI/CD enforcement configured
-
Monitoring dashboard
-
Alert thresholds set
-
Violation response process
-
Regular review schedule