Comprehensive Performance Checklist

Use this checklist for auditing existing sites or ensuring new projects launch with optimal performance. Check items as you implement them.

A. Strategy & Measurement

Performance Culture

  • [ ] Performance goals are documented and shared with the full team
  • [ ] Representative test device chosen (mid-range Android, e.g. Samsung Galaxy A15)
  • [ ] Competitive performance benchmarking completed (target: 20% faster than fastest competitor)
  • [ ] Performance champion or rotating role assigned
  • [ ] Performance metrics included in sprint reviews and team dashboards

Core Web Vitals Targets

  • [ ] LCP ≀ 2.5s at P75 (field data)
  • [ ] INP ≀ 200ms at P75 (field data)
  • [ ] CLS ≀ 0.1 at P75 (field data)
  • [ ] TTFB ≀ 800ms at P75
  • [ ] FCP ≀ 1.8s at P75

Performance Budgets & Monitoring

  • [ ] JavaScript budget set (<200KB gzipped total)
  • [ ] CSS budget set (<50KB gzipped)
  • [ ] Image budget per page defined
  • [ ] Performance budgets enforced in CI/CD (Size-limit, Lighthouse CI, Bundlewatch)
  • [ ] Real User Monitoring (RUM) collecting Core Web Vitals in production
  • [ ] CrUX data monitored in Google Search Console
  • [ ] Synthetic monitoring (Lighthouse/WebPageTest) running on key pages on schedule
  • [ ] Alerting configured for metric regressions

B. JavaScript & Build Pipeline

Build Tools

  • [ ] Using a modern bundler (Vite 8, Rspack, Turbopack, or equivalent)
  • [ ] Linting with Oxlint or Biome (50–100Γ— faster than ESLint)
  • [ ] TypeScript type-checking optimized (tsgo or incremental builds)
  • [ ] Production builds use minification and compression

Code Splitting & Tree Shaking

  • [ ] Route-based code splitting implemented
  • [ ] Heavy components lazy-loaded with React.lazy() or dynamic import()
  • [ ] Barrel files eliminated or optimized (barrel-begone, direct imports)
  • [ ] sideEffects: false configured in package.json where safe
  • [ ] Dead code detection run (Knip) and unused exports removed
  • [ ] Bundle analyzer run to identify largest dependencies

JavaScript Execution

  • [ ] No synchronous third-party scripts in <head>
  • [ ] Long tasks broken up with scheduler.yield() or scheduler.postTask()
  • [ ] Heavy computation offloaded to Web Workers where appropriate
  • [ ] Speculation Rules or prefetch configured for likely next navigations
  • [ ] defer or type="module" used on all non-critical scripts

C. Rendering & Frameworks

Rendering Strategy

  • [ ] Appropriate rendering strategy chosen (SSR/SSG/ISR/Streaming/Islands) for the content type
  • [ ] Server-side rendering used for content-heavy pages
  • [ ] Static generation used for pages that change infrequently
  • [ ] Streaming SSR with Suspense boundaries for progressive loading

React Optimization (if applicable)

  • [ ] React Server Components used for non-interactive content
  • [ ] React Compiler enabled (eliminates manual memoization)
  • [ ] startTransition used for non-urgent state updates
  • [ ] Virtual lists used for long scrollable lists (TanStack Virtual)
  • [ ] Context providers split to minimize re-render blast radius
  • [ ] State management library chosen appropriately (Zustand/Jotai for most cases)
  • [ ] TanStack Query or SWR used for server state (caching, deduplication)

D. Assets & Loading

Images

  • [ ] AVIF served as primary format with WebP and JPEG fallbacks via <picture>
  • [ ] Responsive images implemented with srcset and sizes
  • [ ] LCP image has fetchpriority="high" and is NOT lazy-loaded
  • [ ] Below-fold images have loading="lazy" and decoding="async"
  • [ ] All <img> elements have explicit width and height attributes
  • [ ] LCP image preloaded in <head> (especially if CSS background-image or deep in DOM)
  • [ ] Images compressed with Squoosh, Sharp, or an image CDN
  • [ ] SVGs optimized with SVGO/SVGOMG
  • [ ] Animated GIFs replaced with <video autoplay loop muted playsinline> (AV1/H.264)

CSS

  • [ ] Critical CSS inlined in <head> (<14KB compressed)
  • [ ] Remaining CSS loaded asynchronously
  • [ ] content-visibility: auto applied to off-screen content sections
  • [ ] CSS @layer used for specificity management
  • [ ] Unused CSS removed (PurgeCSS, Coverage tab, or framework tree-shaking)
  • [ ] CSS Modules, vanilla-extract, or Tailwind used (zero-runtime)
  • [ ] No runtime CSS-in-JS (styled-components/Emotion) in new projects
  • [ ] Native CSS nesting used instead of Sass where possible

Modern CSS Replacing JavaScript

  • [ ] Container queries used instead of JS-based ResizeObserver for component responsiveness
  • [ ] :has() used for parent/sibling-based conditional styling instead of JS state
  • [ ] Scroll-driven animations used instead of GSAP/ScrollMagic where possible (with prefers-reduced-motion)
  • [ ] CSS anchor positioning evaluated for tooltips/popovers (replacing Floating UI)
  • [ ] Popover API used for show/hide overlays (replacing custom JS modal logic)
  • [ ] View Transitions API evaluated for page/state transitions
  • [ ] interpolate-size: allow-keywords added to CSS reset
  • [ ] @starting-style used for entry/exit animations from display: none

Fonts

  • [ ] WOFF2 format used exclusively (no TTF/OTF/EOT/SVG)
  • [ ] Fonts self-hosted (not loaded from Google Fonts CDN)
  • [ ] font-display: swap or optional set on all @font-face rules
  • [ ] Font metric overrides configured (size-adjust, ascent-override, descent-override) to minimize CLS
  • [ ] Fonts subsetted to required character ranges with unicode-range
  • [ ] Only necessary weights loaded (2–3 max; consider variable fonts for 3+)
  • [ ] Critical font preloaded with <link rel="preload" as="font" crossorigin>
  • [ ] Icon fonts replaced with SVG icons (Lucide, Heroicons, or inline SVG)
  • [ ] Font files cached with long max-age + immutable

Third-Party Scripts

  • [ ] All third-party scripts load with async or defer (none synchronous)
  • [ ] Facade pattern used for heavy embeds (YouTube, chat widgets, maps)
  • [ ] Third-party scripts loaded after user interaction or after page load where possible
  • [ ] Partytown evaluated for offloading remaining heavy third-party scripts to Web Workers
  • [ ] Consent mode configured (don’t load tracking before consent where legally required)
  • [ ] Tag manager audited quarterly; unused tags removed
  • [ ] Third-party JavaScript budget set and enforced (<100KB compressed)
  • [ ] Content Security Policy (CSP) configured to restrict script sources

Resource Hints

  • [ ] <link rel="preconnect"> added for 2–4 critical third-party origins
  • [ ] <link rel="dns-prefetch"> added for non-critical third-party domains
  • [ ] LCP image preloaded (with imagesrcset/imagesizes for responsive)
  • [ ] Critical font preloaded
  • [ ] modulepreload used for critical JS entry point modules
  • [ ] fetchpriority="high" on LCP element; fetchpriority="low" on non-critical images
  • [ ] Speculation Rules configured for likely next navigations
  • [ ] 103 Early Hints enabled at CDN level (if supported)
  • [ ] No over-preloading (limit to 1–3 truly critical resources)

E. Infrastructure & Networking

Network Protocols & Compression

  • [ ] HTTPS enforced with HSTS (consider HSTS preload)
  • [ ] TLS 1.3 enabled; TLS 1.0/1.1 disabled
  • [ ] HTTP/2 enabled (minimum)
  • [ ] HTTP/3 (QUIC) enabled at CDN or server level
  • [ ] Brotli compression enabled for text assets (CSS, JS, HTML, SVG, JSON)
  • [ ] Zstandard (zstd) compression evaluated for dynamic content
  • [ ] Images, WOFF2 fonts, and video NOT double-compressed via HTTP compression
  • [ ] TCP BBR congestion control enabled on Linux servers

CDN & Caching

  • [ ] CDN in use for all static assets
  • [ ] Fingerprinted assets cached with max-age=31536000, immutable
  • [ ] HTML/API responses use stale-while-revalidate for speed + freshness
  • [ ] Vary: Accept-Encoding set on compressed responses
  • [ ] s-maxage used for CDN-specific cache TTLs where appropriate
  • [ ] Edge functions used for latency-sensitive dynamic logic (auth, geo, A/B)
  • [ ] Service worker caching strategy implemented (Cache First for static, SWR for dynamic)
  • [ ] No caching of personalized/authenticated content in shared caches (private)

F. Quality, Security & DX

Testing & Debugging

  • [ ] Lighthouse CI configured in deployment pipeline with assertion thresholds
  • [ ] Bundle size budgets enforced in CI (Size-limit or Bundlewatch)
  • [ ] Performance regression = blocking PR check (not advisory)
  • [ ] WebPageTest used for deep waterfall analysis of key pages
  • [ ] Chrome DevTools Performance panel used for INP/LCP debugging
  • [ ] Coverage tab checked for unused CSS/JS

Security

  • [ ] HTTPS with HSTS and preload list submission
  • [ ] Content Security Policy deployed (even if Report-Only initially)
  • [ ] Subresource Integrity (SRI) on CDN-hosted scripts
  • [ ] Permissions Policy configured (disable unused features for iframes)
  • [ ] Dependencies audited (npm audit, Socket.dev)
  • [ ] No third-party polyfill CDNs (self-host or use Cloudflare alternative)

Accessibility + Performance

  • [ ] prefers-reduced-motion respected (all animations wrapped in media query)
  • [ ] prefers-reduced-transparency respected where applicable
  • [ ] Semantic HTML used (reducing need for JS-powered interactivity)
  • [ ] Popover API and <dialog> used instead of custom JS modals
  • [ ] Keyboard navigation works without JavaScript where possible

Developer Experience

  • [ ] Fast HMR/Fast Refresh configured (<100ms feedback loop)
  • [ ] Monorepo tooling (Turborepo/Nx) with remote caching if applicable
  • [ ] Performance tested on a real mid-range Android device, not just desktop
  • [ ] Team educated on performance impact of npm install decisions