# Performance Checklist Quick reference checklist for web application performance. Use alongside the `performance-optimization` skill. ## Table of Contents - [Core Web Vitals Targets](#core-web-vitals-targets) - [TTFB Diagnosis](#ttfb-diagnosis) - [Frontend Checklist](#frontend-checklist) - [Backend Checklist](#backend-checklist) - [Measurement Commands](#measurement-commands) - [Common Anti-Patterns](#common-anti-patterns) ## Core Web Vitals Targets | Metric | Good | Needs Work | Poor | |--------|------|------------|------| | 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 `` or `` 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 `` 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 `` (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) - [ ] Non-critical work deferred out of event handlers (e.g. analytics, logging) so the response to the interaction is not delayed - [ ] 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: `` - [ ] `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 (``) for known origins - [ ] `fetchpriority` used on critical non-image resources (e.g., key ``, above-the-fold `