Performance Checklist

Skill

Quick reference checklist for web application performance. Use alongside the `performance-optimization` skill.

addyosmani·Community·v1.0.0

Performance Checklist

Performance Checklist

Quick reference checklist for web application performance. Use alongside the performance-optimization skill.

Table of Contents

Core Web Vitals Targets

MetricGoodNeeds WorkPoor
LCP (Largest Contentful Paint)≤ 2.5s≤ 4.0s> 4.0s
INP (Interaction to Next Paint)≤ 200ms≤ 500ms> 500ms
CLS (Cumulative Layout Shift)≤ 0.1≤ 0.25> 0.25

TTFB Diagnosis

When TTFB is slow (> 800ms), check each component in DevTools Network waterfall:

  • DNS resolution slow → add <link rel="dns-prefetch"> or <link rel="preconnect"> for known origins
  • TCP/TLS handshake slow → enable HTTP/2, consider edge deployment, verify keep-alive
  • Server processing slow → profile backend, check slow queries, add caching

Frontend Checklist

Images

  • Images use modern formats (WebP, AVIF)
  • Images are responsively sized (srcset and sizes)
  • Images and <source> elements have explicit width and height (prevents CLS in art direction)
  • Below-the-fold images use loading="lazy" and decoding="async"
  • Hero/LCP images use fetchpriority="high" and no lazy loading

JavaScript

  • Bundle size under 200KB gzipped (initial load)
  • Code splitting with dynamic import() for routes and heavy features
  • Tree shaking enabled (verify dependency ships ESM and marks sideEffects: false)
  • No blocking JavaScript in <head> (use defer or async)
  • Heavy computation offloaded to Web Workers (if applicable)
  • React.memo() on expensive components that re-render with same props
  • useMemo() / useCallback() only where profiling shows benefit
  • Long tasks (> 50ms) broken up to keep the main thread available — main lever for INP
  • yieldToMain pattern used inside long-running loops so input events can run between chunks
  • Modern scheduling APIs used where available: scheduler.yield() (preferred), scheduler.postTask() with priorities, isInputPending() to yield only when needed
  • requestIdleCallback for deferrable, non-urgent work (analytics flush, prefetch, warmup)
  • Third-party scripts loaded with async / defer, audited for size, and fronted by a facade when heavy (chat widgets, embeds)

CSS

  • Critical CSS inlined or preloaded
  • No render-blocking CSS for non-critical styles
  • No CSS-in-JS runtime cost in production (use extraction)

Fonts

  • Limited to 2–3 font families, 2–3 weights each (every additional weight is another request)
  • WOFF2 format only (smallest, universal support — skip WOFF/TTF/EOT)
  • Self-hosted when possible (third-party font CDNs add DNS + TCP + TLS round-trips)
  • LCP-critical fonts preloaded: <link rel="preload" as="font" type="font/woff2" crossorigin>
  • font-display: swap (or optional for non-critical) to avoid FOIT blocking render
  • Subsetted via unicode-range to ship only the glyphs each page needs
  • Variable fonts considered when multiple weights/styles are required (one file replaces many)
  • Fallback font metrics adjusted with size-adjust, ascent-override, descent-override to reduce CLS on font swap
  • System font stack considered before any custom font

Network

  • Static assets cached with long max-age + content hashing
  • API responses cached where appropriate (Cache-Control)
  • HTTP/2 or HTTP/3 enabled
  • Resources preconnected (<link rel="preconnect">) for known origins
  • fetchpriority used on critical non-image resources (e.g., key <link rel="preload">, above-the-fold <script>) — not only on <img>
  • No unnecessary redirects

Rendering

  • No layout thrashing (forced synchronous layouts)
  • Animations use transform and opacity (GPU-accelerated)
  • Long lists use virtualization (e.g., react-window)
  • No unnecessary full-page re-renders
  • Off-screen sections use content-visibility: auto with contain-intrinsic-size to skip layout/paint of non-visible areas
  • No unload event handlers and no Cache-Control: no-store on HTML responses — preserves back/forward cache (bfcache) eligibility

Backend Checklist

Database

  • No N+1 query patterns (use eager loading / joins)
  • Queries have appropriate indexes
  • List endpoints paginated (never SELECT * FROM table)
  • Connection pooling configured
  • Slow query logging enabled

API

  • Response times < 200ms (p95)
  • No synchronous heavy computation in request handlers
  • Bulk operations instead of loops of individual calls
  • Response compression (gzip/brotli)
  • Appropriate caching (in-memory, Redis, CDN)

Infrastructure

  • CDN for static assets
  • Server located close to users (or edge deployment)
  • Horizontal scaling configured (if needed)
  • Health check endpoint for load balancer

Measurement Commands

# Lighthouse CLI
npx lighthouse https://localhost:3000 --output json --output-path ./report.json

# Bundle analysis
npx webpack-bundle-analyzer stats.json
# or for Vite:
npx vite-bundle-visualizer

# Check bundle size
npx bundlesize

# Web Vitals in code
import { onLCP, onINP, onCLS } from 'web-vitals';
onLCP(console.log);
onINP(console.log);
onCLS(console.log);

Common Anti-Patterns

Anti-PatternImpactFix
N+1 queriesLinear DB load growthUse joins, includes, or batch loading
Unbounded queriesMemory exhaustion, timeoutsAlways paginate, add LIMIT
Missing indexesSlow reads as data growsAdd indexes for filtered/sorted columns
Layout thrashingJank, dropped framesBatch DOM reads, then batch writes
Unoptimized imagesSlow LCP, wasted bandwidthUse WebP, responsive sizes, lazy load
Large bundlesSlow Time to InteractiveCode split, tree shake, audit deps
Blocking main threadPoor INP, unresponsive UIChunk long tasks with scheduler.yield() / yieldToMain, offload to Web Workers
Memory leaksGrowing memory, eventual crashClean up listeners, intervals, refs

Imported from https://github.com/addyosmani/agent-skills by addyosmani. Licensed under MIT. Source: https://github.com/addyosmani/agent-skills/blob/main/references/performance-checklist.md