Performance Optimization

SkillDatabases & data

Web performance optimization. Covers frontend, backend, and database optimization. Use for performance reviews.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Performance Optimization skill

What this skill tells your AI

The instructions your AI receives, as published by claude-dev-suite/claude-dev-suite in skills/best-practices/performance/SKILL.md and read by ahel’s review.

Deep Knowledge: Use mcp__documentation__fetch_docs with technology: performance for comprehensive documentation.

When NOT to Use This Skill

This skill focuses on runtime performance optimization. Do NOT use for:

  • Algorithm optimization - Use computer science/data structures fundamentals
  • Code readability - Use clean-code skill (don't sacrifice readability for micro-optimizations)
  • Build time optimization - Use build tool specific skills (Vite, Webpack, etc.)
  • Developer experience - Use DX-focused skills and tooling
  • Security hardening - Use security-specific skills (performance != security)

Anti-Patterns

Anti-PatternWhy It's BadPerformance Solution
Premature OptimizationWaste time on non-bottlenecksMeasure first, optimize bottlenecks only
**SELECT ***Fetches unnecessary dataSelect only needed columns
N+1 QueriesMultiple DB roundtripsUse joins or eager loading
No CachingRepeated expensive computationsCache at appropriate layer (memory, Redis, CDN)
Blocking OperationsHolds up main threadUse async/background jobs
Large BundleSlow initial loadCode splitting, lazy loading
No Image OptimizationHuge assets over networkCompress, modern formats (WebP, AVIF), lazy load
Missing IndexesFull table scansAdd indexes on queried columns
Memory LeaksUnbounded growthClean up listeners, close connections, clear refs
Synchronous I/OBlocks event loopUse async I/O operations

Quick Troubleshooting

IssueDiagnosticSolution
Slow page loadCheck Network tabOptimize images, enable compression, use CDN
Poor LCPLighthouse auditPreload critical resources, optimize largest element
High INPPerformance profilerDebounce handlers, use web workers, reduce JS
Layout shifts (CLS)Layout Shift RegionsSet dimensions on images/embeds, avoid dynamic content
Slow API responseAPM tools, loggingAdd database indexes, cache responses, optimize queries
High memory usageMemory profilerFix leaks, clear intervals/listeners, use weak refs
Large bundleBundle analyzerCode split, tree shake, lazy load routes
Slow database queryEXPLAIN ANALYZEAdd indexes, rewrite query, partition table

Frontend Performance

Core Web Vitals

MetricTargetMeasurement
LCP (Largest Contentful Paint)< 2.5sLargest visible element
INP (Interaction to Next Paint)< 200msInput responsiveness
CLS (Cumulative Layout Shift)< 0.1Visual stability

Optimization Techniques

// Code splitting
const Dashboard = lazy(() => import('./Dashboard'));

// Image optimization
<Image
  src="/hero.jpg"
  width={1200}
  height={600}
  priority  // Above fold
  placeholder="blur"
/>

// Memoization
const MemoizedComponent = memo(ExpensiveComponent);
const memoizedValue = useMemo(() => computeExpensive(a, b), [a, b]);
const memoizedFn = useCallback(() => handleClick(id), [id]);

// Virtual lists for long lists
<VirtualList items={items} itemHeight={50} />

Backend Performance

// N+1 prevention
const usersWithPosts = await prisma.user.findMany({
  include: { posts: true }  // Single query with join
});

// Caching
const cached = await redis.get(key);
if (cached) return JSON.parse(cached);
const data = await db.query();
await redis.setex(key, 3600, JSON.stringify(data));

// Connection pooling
const pool = new Pool({ max: 20 });

// Async processing
await queue.add('sendEmail', { userId });

Database Performance

-- Use EXPLAIN ANALYZE
EXPLAIN ANALYZE SELECT * FROM users WHERE email = 'x';

-- Add indexes for frequently queried columns
CREATE INDEX idx_users_email ON users(email);

-- Partial indexes
CREATE INDEX idx_active_users ON users(email) WHERE is_active = true;

-- Avoid SELECT *
SELECT id, name, email FROM users;

-- Pagination
SELECT * FROM users ORDER BY id LIMIT 20 OFFSET 0;

Checklist

AreaCheck
ImagesOptimized, lazy loaded, proper format
JS BundleCode split, tree shaken, minified
CSSCritical CSS inline, unused removed
FontsPreloaded, subset, font-display
CachingCDN, browser cache, API cache
DatabaseIndexes, query optimization

Production Readiness

Monitoring Setup

// Web Vitals reporting
import { onCLS, onINP, onLCP, onFCP, onTTFB } from 'web-vitals';

function sendToAnalytics(metric: Metric) {
  const body = JSON.stringify({
    name: metric.name,
    value: metric.value,
    id: metric.id,
    page: window.location.pathname,
  });

  // Use sendBeacon for reliability
  navigator.sendBeacon('/analytics', body);
}

onCLS(sendToAnalytics);
onINP(sendToAnalytics);
onLCP(sendToAnalytics);
onFCP(sendToAnalytics);
onTTFB(sendToAnalytics);

Performance Budget

// webpack.config.js or vite.config.ts
{
  performance: {
    maxAssetSize: 250000, // 250KB
    maxEntrypointSize: 500000, // 500KB
    hints: 'error',
  },
}

// Lighthouse CI budget
// lighthouserc.js
module.exports = {
  ci: {
    collect: {
      url: ['http://localhost:3000/'],
    },
    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-blocking-time': ['error', { maxNumericValue: 300 }],
      },
    },
  },
};

Backend Optimization

// Response compression
import compression from 'compression';
app.use(compression({ threshold: 1024 }));

// Response caching headers
function setCacheHeaders(res: Response, maxAge: number) {
  res.setHeader('Cache-Control', `public, max-age=${maxAge}, stale-while-revalidate=${maxAge * 2}`);
  res.setHeader('Vary', 'Accept-Encoding');
}

// Streaming responses
async function streamLargeData(res: Response) {
  const stream = db.users.findMany().cursor();

  res.setHeader('Content-Type', 'application/json');
  res.write('[');

  let first = true;
  for await (const user of stream) {
    if (!first) res.write(',');
    res.write(JSON.stringify(user));
    first = false;
  }

  res.write(']');
  res.end();
}

// Query optimization
const users = await prisma.user.findMany({
  select: { id: true, name: true, email: true }, // Only needed fields
  where: { isActive: true },
  take: 20,
  orderBy: { createdAt: 'desc' },
});

Database Optimization

-- Composite indexes for common queries
CREATE INDEX idx_users_active_created
ON users(is_active, created_at DESC)
WHERE is_active = true;

-- Query analysis
EXPLAIN (ANALYZE, BUFFERS, FORMAT TEXT)
SELECT * FROM users WHERE email = 'test@example.com';

-- Connection pooling configuration
-- pgbouncer.ini
[pgbouncer]
pool_mode = transaction
default_pool_size = 20
max_client_conn = 100

CI Performance Testing

# .github/workflows/performance.yml
name: Performance

on:
  pull_request:
    branches: [main]

jobs:
  lighthouse:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Build
        run: npm run build

      - name: Run Lighthouse CI
        uses: treosh/lighthouse-ci-action@v10
        with:
          configPath: ./lighthouserc.js
          uploadArtifacts: true

  bundle-size:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Build
        run: npm run build

      - name: Check bundle size
        uses: siddharthkp/bundlesize@v2
        with:
          files: 'dist/*.js'
          maxSize: '250KB'

Caching Strategy

// Cache layers
const cacheStrategy = {
  // L1: In-memory (fastest, smallest)
  memory: new LRUCache({ max: 1000, ttl: 60000 }),

  // L2: Redis (fast, larger)
  redis: new Redis({ maxRetriesPerRequest: 3 }),

  // L3: CDN (edge caching)
  cdn: {
    cacheControl: 'public, max-age=31536000, immutable', // Static assets
    staleWhileRevalidate: 'public, max-age=60, stale-while-revalidate=600', // API
  },
};

async function getCachedData<T>(key: string, fetcher: () => Promise<T>): Promise<T> {
  // Check memory
  const memoryHit = cacheStrategy.memory.get(key);
  if (memoryHit) return memoryHit as T;

  // Check Redis
  const redisHit = await cacheStrategy.redis.get(key);
  if (redisHit) {
    const data = JSON.parse(redisHit);
    cacheStrategy.memory.set(key, data);
    return data;
  }

  // Fetch and cache
  const data = await fetcher();
  cacheStrategy.memory.set(key, data);
  await cacheStrategy.redis.setex(key, 300, JSON.stringify(data));

  return data;
}

Monitoring Metrics

MetricTarget
LCP< 2.5s
INP< 200ms
CLS< 0.1
TTFB< 200ms
API p95 latency< 500ms
Database query time< 100ms
Cache hit rate> 90%

Production Checklist

  • Core Web Vitals monitored
  • Performance budget set
  • Lighthouse CI in pipeline
  • Bundle size monitoring
  • Image optimization
  • Code splitting enabled
  • Compression enabled
  • Caching strategy defined
  • Database indexes optimized
  • CDN configured

Reference Documentation

Signals

GitHub stars
33
Forks
6
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
performance-claude-dev-suite
Source
github.com/claude-dev-suite/claude-dev-suite