web-performance
Web Performance Optimization
Reference for diagnosing and improving web application performance, covering measurement, asset delivery, rendering, caching, and monitoring.
1. Core Web Vitals
Largest Contentful Paint (LCP)
Measures time until the largest visible content element (image, video poster, or text block) finishes rendering.
- Good: <= 2.5s | Needs improvement: <= 4.0s | Poor: > 4.0s
- Causes of poor LCP: slow TTFB, render-blocking CSS/JS, slow hero image loads, client-side rendering delays.
Interaction to Next Paint (INP)
Replaced FID in March 2024. Measures latency of all click, tap, and keyboard interactions, reports near the worst case.
- Good: <= 200ms | Needs improvement: <= 500ms | Poor: > 500ms
- Causes of poor INP: long main-thread tasks, excessive DOM size, layout thrashing, heavy event handlers.
Cumulative Layout Shift (CLS)
Measures unexpected layout shifts across the page lifespan.
- Good: <= 0.1 | Needs improvement: <= 0.25 | Poor: > 0.25
- Causes of poor CLS: images/iframes without dimensions, dynamically injected content above the fold, font reflow (FOUT), late-loading CSS.
2. Measurement Tools
Lighthouse and PageSpeed Insights
- Run Lighthouse from Chrome DevTools, CLI (
npx lighthouse URL), or the Node API. - PageSpeed Insights (
pagespeed.web.dev) combines lab (Lighthouse) and field (CrUX) data. - Score weights: LCP 25%, TBT 30%, CLS 25%, FCP 10%, Speed Index 10%.
- Lab data is reproducible but synthetic. Field data reflects real users but requires traffic volume.
Chrome DevTools Performance Tab
- Record a page load or interaction; inspect the flame chart for long tasks (>50ms).
- Check the "Timings" lane for LCP, FCP, and DCL markers.
- Use the "Coverage" tab to find unused CSS and JavaScript.
WebPageTest
- Test from multiple locations on real devices and browsers.
- Waterfall view shows DNS, connect, TLS, TTFB, and download phases per resource.
- Filmstrip view shows visual progress frame by frame.
- Use scripted tests for multi-step flows; compare runs side-by-side.
3. Image Optimization
Modern formats: WebP is 25-35% smaller than JPEG. AVIF is 20-50% smaller than WebP for photos. Use <picture> for format negotiation:
<picture>
<source type="image/avif" srcset="photo.avif">
<source type="image/webp" srcset="photo.webp">
<img src="photo.jpg" alt="Description" width="800" height="600">
</picture>
Responsive images: Serve different sizes via srcset and sizes to avoid oversized downloads:
<img srcset="photo-400.jpg 400w, photo-800.jpg 800w, photo-1200.jpg 1200w"
sizes="(max-width: 600px) 400px, (max-width: 1000px) 800px, 1200px"
src="photo-800.jpg" alt="Description" width="800" height="600">
Lazy loading: Use loading="lazy" on offscreen images. Do not lazy-load the LCP image; use fetchpriority="high" on it instead.
Image CDNs (Cloudinary, imgix, Cloudflare Images) resize, compress, and convert images on the fly via URL parameters.
4. JavaScript Performance
Code Splitting
// Route-based splitting in React
const Dashboard = React.lazy(() => import('./pages/Dashboard'));
// Manual dynamic import
const { Editor } = await import('./Editor');
- Split by route so users only download code for the current page.
- Split heavy libraries (charting, PDF, maps) into separate chunks.
Tree Shaking
- Use ES module syntax (
import/export) so bundlers can eliminate dead code. - Avoid
import * as libwhen you only need specific functions. - Ensure third-party packages provide an ES module build (
"module"field in package.json). - Mark packages as side-effect-free:
"sideEffects": falsein package.json.
Reducing Main Thread Work
- Break long tasks using
requestIdleCallback,scheduler.postTask, orsetTimeout(fn, 0). - Move heavy computation to Web Workers.
- Avoid synchronous layout reads inside loops (layout thrashing).
- Defer non-critical JS with
<script defer>or<script type="module">.
5. CSS Performance
Critical CSS: Inline above-the-fold CSS in <head>, load the full stylesheet asynchronously:
<head>
<style>/* Critical CSS inlined here */</style>
<link rel="preload" href="styles.css" as="style" onload="this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="styles.css"></noscript>
</head>
Tools like the critical npm package can extract critical CSS automatically.
Reducing render-blocking CSS: Split CSS per route, use media attributes on non-applicable stylesheets, avoid @import (it creates sequential requests).
CSS Containment:
.card {
contain: layout style paint;
content-visibility: auto;
contain-intrinsic-size: 0 200px;
}
content-visibility: auto skips rendering for offscreen elements. Provide contain-intrinsic-size to preserve scroll position.
6. Font Loading
@font-face {
font-family: 'CustomFont';
src: url('custom.woff2') format('woff2');
font-display: swap; /* or optional, fallback */
}
swap: shows fallback text immediately, swaps on load. Risk of layout shift.optional: uses fallback for the whole visit if the font does not load quickly. Best for non-critical fonts.- Preload critical fonts:
<link rel="preload" href="custom.woff2" as="font" type="font/woff2" crossorigin>. - Subset unused glyphs with
pyftsubset,glyphhanger, or Google Fonts&text=parameter. - Variable fonts replace multiple weight/style files with a single file.
7. Caching Strategies
Cache-Control Headers
Cache-Control: public, max-age=31536000, immutable # hashed assets
Cache-Control: no-cache # HTML (always revalidate)
Cache-Control: private, max-age=0, must-revalidate # API responses
immutable: skip revalidation on reload; safe only for content-hashed URLs.no-cache: always revalidate (not the same asno-store).stale-while-revalidate: serve stale content while fetching fresh copy in the background.
ETags
ETags enable conditional requests via If-None-Match. The server responds 304 Not Modified if unchanged, saving bandwidth.
Service Workers
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request).then((cached) => {
return cached || fetch(event.request).then((response) => {
const clone = response.clone();
caches.open('v1').then((cache) => cache.put(event.request, clone));
return response;
});
})
);
});
Strategies: cache-first (static assets), network-first (API calls), stale-while-revalidate (balance of speed and freshness).
8. CDN Setup and Configuration
- Serve static assets from edge nodes geographically close to users.
- Use a cookieless subdomain for static assets to reduce request header size.
- Match CDN cache TTLs to your Cache-Control headers.
- Enable Brotli/gzip compression at the edge.
- Use CDN-level image optimization where available.
- Tie cache invalidation/purge workflows to your deployment pipeline.
9. Compression
| Algorithm | Savings vs. Uncompressed | Browser Support | Notes |
|---|---|---|---|
| gzip | 60-80% | Universal | Baseline everywhere |
| Brotli | 15-25% smaller than gzip | All modern browsers | Best for pre-compressed static assets |
| zstd | Comparable to Brotli | Chrome 123+, Firefox 126+ | Faster compression, emerging support |
- Pre-compress static assets at build time (Brotli level 11) for best ratios.
- Use dynamic compression at server/CDN for HTML and API responses.
- Set
Vary: Accept-Encodingso caches store separate versions per encoding.
10. Preloading and Prefetching
<link rel="preload" href="critical.js" as="script">
<link rel="preload" href="hero.avif" as="image" type="image/avif">
<link rel="prefetch" href="/next-page.js">
<link rel="preconnect" href="https://api.example.com">
<link rel="dns-prefetch" href="https://analytics.example.com">
- preload: high-priority fetch for current-page resources. Limit to 2-3 critical items.
- prefetch: low-priority speculative fetch for next-navigation resources.
- preconnect: early DNS + TCP + TLS to third-party origins.
- dns-prefetch: DNS-only resolution, lighter than preconnect, wider support.
- Use
fetchpriority="high"on the LCP image,fetchpriority="low"on non-critical resources.
11. Rendering Strategies
Server-Side Rendering (SSR): Server generates full HTML per request. Faster FCP, better SEO, but higher server load. Frameworks: Next.js, Nuxt, SvelteKit, Remix.
Static Site Generation (SSG): Pages pre-rendered at build time, served from CDN. Fastest TTFB. Not suitable for highly dynamic content. ISR (Next.js) bridges the gap.
Client-Side Rendering (CSR): Minimal HTML shell; JS fetches data and renders. Slower initial paint. Good for authenticated apps behind login. Mitigate with code splitting and skeleton screens.
Streaming and Partial Hydration: Streaming SSR sends HTML in chunks as data resolves. Partial hydration only hydrates interactive components. React Server Components mix server and client rendering in one tree.
12. Bundle Analysis
webpack-bundle-analyzer:
npx webpack --profile --json > stats.json
npx webpack-bundle-analyzer stats.json
Look for duplicate libraries, oversized dependencies, and unstripped locale data.
source-map-explorer:
npx source-map-explorer dist/main.js dist/main.js.map
Works with any bundler that produces source maps.
Import Cost editor plugins show the size of each import inline during development.
13. Database Query Impact on Page Load
Slow queries directly increase TTFB for SSR pages and API response times for CSR apps.
- Add indexes for columns in WHERE, JOIN, and ORDER BY clauses.
- Avoid N+1 query patterns; use eager loading or batched queries.
- Cache frequently accessed, rarely changing data in Redis or Memcached.
- Use APM tools (Datadog, New Relic, Sentry) to identify slow queries.
- Run independent data fetches in parallel for SSR pages.
14. Real User Monitoring (RUM)
- The
web-vitalsJS library reports LCP, INP, CLS, FCP, and TTFB to your analytics endpoint. - The PerformanceObserver API provides raw timing data for resources, long tasks, and layout shifts.
- Google CrUX aggregates field data from Chrome users, accessible via BigQuery or the CrUX API.
- Commercial RUM: Datadog RUM, New Relic Browser, Speedcurve, Sentry Performance.
- Segment data by device type, connection speed, and geography.
- Track custom timings for business-critical interactions (time to first search result, checkout).
15. Performance Budgets
| Metric | Example Budget |
|---|---|
| Total JS (compressed) | < 200 KB |
| Total CSS (compressed) | < 50 KB |
| Total images per page | < 500 KB |
| Total font files | < 100 KB |
| LCP | < 2.5s |
| INP | < 200ms |
| CLS | < 0.1 |
| Total page weight | < 1 MB |
Enforcement: bundlesize or size-limit in CI, Lighthouse CI assertions, webpack performance.maxAssetSize.
16. Common Wins
- Reduce HTTP requests: combine small files, use SVG symbol sheets, inline critical resources.
- Minification: Terser for JS, cssnano or Lightning CSS for CSS.
- HTTP/2 and HTTP/3: multiplexing eliminates domain sharding; many small files perform well.
- Lazy load offscreen content: images, iframes, below-fold components.
- Remove unused dependencies: audit with
depcheckorknip. - Avoid layout shifts: set explicit dimensions on images, videos, and ad slots.
- Reduce third-party impact: load scripts async, use facades for heavy embeds (YouTube, chat).
- 103 Early Hints: send preload hints before the full response is ready.
17. Performance Audit Checklist
- Measure with Lighthouse, WebPageTest, and field data (CrUX or RUM).
- Set performance budgets for bundle sizes and Core Web Vitals.
- Optimize LCP: preload the element, serve modern formats, set
fetchpriority="high". - Reduce INP: break long tasks, debounce handlers, minimize DOM size.
- Fix CLS: set dimensions on media, avoid injecting content above the fold.
- Enable Brotli or gzip on all text resources.
- Configure caching with content-hashed filenames and long max-age.
- Implement code splitting and lazy loading for routes and heavy components.
- Inline critical CSS, defer non-critical stylesheets.
- Preload fonts, use
font-display: swaporoptional, subset unused glyphs. - Serve static assets through a CDN.
- Analyze bundles for duplicate or oversized dependencies.
- Optimize database queries affecting TTFB.
- Deploy RUM for continuous real-user monitoring.
- Audit third-party scripts for size and main-thread impact.
More from 1mangesh1/dev-skills-collection
curl-http
HTTP request construction and API testing with curl and HTTPie. Use when user asks to "test API", "make HTTP request", "curl POST", "send request", "test endpoint", "debug API", "upload file", "check response time", "set auth header", "basic auth with curl", "send JSON", "test webhook", "check status code", "follow redirects", "rate limit testing", "measure API latency", "stress test endpoint", "mock API response", or any HTTP calls from the command line.
28database-indexing
Database indexing internals, index type selection, query plan analysis, and write-overhead tradeoffs across PostgreSQL, MySQL, and MongoDB. Use when user asks to "optimize queries", "create indexes", "fix slow queries", "read EXPLAIN output", "reduce query time", "index strategy", "database performance", "composite index", "covering index", "partial index", "index bloat", "unused indexes", or needs help diagnosing and resolving database performance problems.
13testing-strategies
Testing strategies, patterns, and methodologies across the full testing spectrum. Use when asked about unit tests, integration tests, e2e tests, test pyramid, mocking, test doubles, TDD, property-based testing, snapshot testing, test coverage, mutation testing, contract testing, performance testing, test data management, CI/CD testing, flaky tests, test anti-patterns, test organization, test isolation, test fixtures, test parameterization, or any testing strategy, approach, or methodology.
10secret-scanner
This skill should be used when the user asks to "scan for secrets", "find API keys", "detect credentials", "check for hardcoded passwords", "find leaked tokens", "scan for sensitive keys", "check git history for secrets", "audit repository for credentials", or mentions secret detection, credential scanning, API key exposure, token leakage, password detection, or security key auditing.
10terraform
Terraform infrastructure as code for provisioning, modules, state management, and workspaces. Use when user asks to "create infrastructure", "write Terraform", "manage state", "create module", "import resource", "plan changes", or any IaC tasks.
10kubernetes
Kubernetes and kubectl mastery for deployments, services, pods, debugging, and cluster management. Use when user asks to "deploy to k8s", "create deployment", "debug pod", "kubectl commands", "scale service", "check pod logs", "create ingress", or any Kubernetes tasks.
10