Playbook Performance

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. 1. Make it work — Correct behavior first
  2. 2. Make it right — Clean, maintainable code
  3. 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)