Performance Optimization Playbook
Measure first, optimize second. Evidence-based performance improvements for frontend and backend systems.
# agent_prompt
Copy this prompt and give it to your AI agent:
"Apply these performance practices:
1. Measure before optimizing (never guess)
2. Optimize the critical path first
3. Use caching at appropriate layers
4. Lazy load non-critical resources
5. Minimize network requests (batch/combine)
6. Use appropriate data structures (O(1) vs O(n))
7. Profile memory usage for long-running processes"
# core_philosophy
"Premature optimization is the root of all evil. We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%." — Donald Knuth
- 1. Make it work — Correct behavior first
- 2. Make it right — Clean, maintainable code
- 3. Make it fast — Optimize measured bottlenecks
# frontend_performance
Core Web Vitals
Google's metrics for user experience. These directly impact SEO.
LCP
< 2.5s
Largest Contentful Paint
FID
< 100ms
First Input Delay
CLS
< 0.1
Cumulative Layout Shift
Bundle Optimization
Reduce JavaScript payload for faster load times.
// Code splitting with dynamic imports
const HeavyComponent = lazy(() => import('./HeavyComponent'));
// Tree shaking - import only what you need
import { debounce } from 'lodash-es'; // ✅ Tree-shakeable
import _ from 'lodash'; // ❌ Imports everything
// Bundle analysis
// npm run build -- --analyze
// Look for: large dependencies, duplicates, unused code - • Code split by route: Each page loads only its code
- • Tree shake: Use ES modules, import specifically
- • Compress: gzip/brotli for text assets
- • Minify: Remove whitespace, shorten names
Image Optimization
Images are often the largest payload. Optimize aggressively.
<!-- Responsive images with srcset -->
<img
src="image-800.webp"
srcset="
image-400.webp 400w,
image-800.webp 800w,
image-1200.webp 1200w"
sizes="(max-width: 600px) 400px, 800px"
loading="lazy"
decoding="async"
alt="Description"
/>
<!-- Or use picture for format fallbacks -->
<picture>
<source srcset="image.avif" type="image/avif">
<source srcset="image.webp" type="image/webp">
<img src="image.jpg" alt="Description">
</picture> - • Modern formats: WebP (93% support), AVIF (85% support)
- • Lazy loading: loading="lazy" for below-fold images
- • Proper sizing: Don't serve 2000px images for 200px spaces
- • CDN delivery: Edge caching for global performance
# backend_performance
Caching Strategy
The fastest request is one you don't have to make.
Cache Hierarchy
Browser Cache → CDN → Application Cache → Database Cache → Database 1. Browser: Cache-Control headers, ETags 2. CDN: Edge caching for static assets 3. Application: Redis/Memcached for computed data 4. Database: Query cache, connection pooling
// Application-level caching with Redis
async function getUser(id) {
const cacheKey = `user:$${id}`;
// Try cache first
const cached = await redis.get(cacheKey);
if (cached) return JSON.parse(cached);
// Cache miss - fetch from DB
const user = await db.users.findById(id);
// Store in cache (expire in 5 minutes)
await redis.setex(cacheKey, 300, JSON.stringify(user));
return user;
} Database Performance
The database is often the bottleneck. Optimize queries and connections.
- Connection pooling: Reuse connections instead of creating new ones. Pool size = (cores * 2) + disk spindles
- Query optimization: Use EXPLAIN ANALYZE, add appropriate indexes, avoid N+1 queries
- Read replicas: Route read queries to replicas, writes to primary
- Pagination: Never load unbounded result sets. Use cursor-based pagination for large datasets
Async Processing
Move slow operations out of the request path.
// Instead of processing in the request:
app.post('/order', async (req, res) => {
const order = await createOrder(req.body);
// ❌ Don't do this in the request
// await sendEmail(order);
// await updateInventory(order);
// await notifyWarehouse(order);
// ✅ Queue for background processing
await queue.add('process-order', { orderId: order.id });
res.json(order); // Return immediately
});
// Background worker processes the queue
queue.process('process-order', async (job) => {
const order = await getOrder(job.data.orderId);
await sendEmail(order);
await updateInventory(order);
await notifyWarehouse(order);
}); # profiling_tools
Measurement Tools
Frontend
- • Lighthouse: Chrome DevTools → Lighthouse tab
- • WebPageTest: webpagetest.org for real-world metrics
- • Performance API: window.performance.timing
- • React DevTools: Profiler for component render times
Backend
- • Node.js: --inspect flag, clinic.js, 0x for flame graphs
- • Python: cProfile, py-spy, memory_profiler
- • Database: EXPLAIN ANALYZE, pg_stat_statements
- • APM: New Relic, Datadog, or open-source alternatives
# performance_budgets
Set concrete targets and fail builds that exceed them.
// Example: Lighthouse CI config
module.exports = {
ci: {
assert: {
assertions: {
'categories:performance': ['error', { minScore: 0.9 }],
'first-contentful-paint': ['error', { maxNumericValue: 2000 }],
'largest-contentful-paint': ['error', { maxNumericValue: 2500 }],
'cumulative-layout-shift': ['error', { maxNumericValue: 0.1 }],
'total-byte-weight': ['error', { maxNumericValue: 500000 }],
}
}
}
} Frontend Budgets
- • Initial JS: < 200KB (compressed)
- • Total page weight: < 1MB
- • LCP: < 2.5s
- • TTI: < 3.5s on 3G
Backend Budgets
- • API response: < 200ms p95
- • Database queries: < 50ms p95
- • Error rate: < 0.1%
- • Memory growth: 0 (no leaks)