Web Performance Checklist for 2026
Core Web Vitals, image optimization, bundle size, server response — a practical checklist for web performance in 2026.

A slow site loses users. Google has the numbers to prove it — the probability of bounce increases 32% when page load goes from 1 to 3 seconds. At 5 seconds, that probability jumps 90%. Performance isn't a feature. It's the baseline.
The tricky part is knowing where to start. "Optimize performance" sounds great until you're staring at a waterfall chart with no idea what to fix first. This is a checklist, organized by what actually moves the needle in 2026.
Core Web Vitals
Google's performance metrics that directly affect search rankings. Since FID was replaced by INP in 2024, the measurement criteria shifted significantly.
LCP (Largest Contentful Paint)
Time until the largest content element renders on screen. Usually the hero image or a big text block.
- Good: 2.5s or less
- Needs improvement: 2.5–4s
- Poor: Over 4s
Most LCP problems come from four places:
- Slow server response. High TTFB (Time to First Byte) delays everything downstream.
- Render-blocking resources. CSS and JS files that hold up the first paint.
- Slow resource loading. Large hero images, no CDN.
- Client-side rendering. Content only appears after JS fully loads and executes.
If your LCP element is an image, set fetchpriority="high" and add a preload hint. This alone can shave hundreds of milliseconds.
<link rel="preload" as="image" href="/hero.webp" fetchpriority="high">
INP (Interaction to Next Paint)
Measures responsiveness across the entire page lifecycle — every click, tap, and keystroke, not just the first interaction like FID did.
- Good: 200ms or less
- Needs improvement: 200–500ms
- Poor: Over 500ms
The usual culprit is JavaScript hogging the main thread. Any task longer than 50ms blocks user input.
Ways to fix it:
- Break long tasks with
requestIdleCallbackorscheduler.yield() - Move heavy computation to Web Workers
- Prevent unnecessary re-renders (in React:
memo,useMemo,useCallback) - Minimize DOM changes inside event handlers
CLS (Cumulative Layout Shift)
The cumulative score of unexpected layout movement. That annoying experience where text jumps down because an ad loaded above it.
- Good: 0.1 or less
- Needs improvement: 0.1–0.25
- Poor: Over 0.25
To keep CLS low:
- Always set
widthandheighton images (or useaspect-ratioin CSS) - Use
font-display: swapwithsize-adjustfor web fonts to minimize fallback shift - Reserve minimum height for ad slots
- Pre-allocate space before injecting dynamic content
Image Optimization
Images often account for more than half of page weight. This is usually the highest-impact area to work on.
Format Selection
Recommended formats in 2026:
- AVIF — Most efficient. 20–30% smaller than WebP at equivalent quality. Browser support is solid now.
- WebP — Second best. Good fallback for older browsers.
- SVG — Always use for icons, logos, and illustrations.
- PNG/JPEG — Last resort fallback.
Use <picture> for format fallbacks:
<picture>
<source srcset="/image.avif" type="image/avif">
<source srcset="/image.webp" type="image/webp">
<img src="/image.jpg" alt="Description" width="800" height="600">
</picture>
If you're on Next.js, the next/image component handles this automatically.
Lazy Loading
No reason to load images below the fold upfront.
<img src="/below-fold.webp" loading="lazy" alt="Description">
But never use loading="lazy" on the LCP element (hero image, etc.) — it makes things slower. LCP images should be loading="eager" (the default) with fetchpriority="high".
Responsive Images
Loading a 2000px desktop image on mobile is pure waste.
<img
srcset="/img-400.webp 400w, /img-800.webp 800w, /img-1200.webp 1200w"
sizes="(max-width: 640px) 400px, (max-width: 1024px) 800px, 1200px"
src="/img-800.webp"
alt="Description"
>
Reducing Bundle Size
Large JavaScript bundles mean slow parsing and execution, especially painful on mobile devices.
Know What You're Shipping
Start with bundle analysis. You can't fix what you can't see.
# Next.js
npx @next/bundle-analyzer
# Vite
npx vite-bundle-visualizer
# General
npx source-map-explorer dist/assets/*.js
More often than not, a handful of npm packages eat up most of the bundle. moment.js with all its locales, full lodash imports, oversized date libraries — the usual suspects.
Tree Shaking
Removes unused code from the bundle. Works automatically with ESM (ES Modules), but CommonJS modules don't tree-shake.
// Bad — imports all of lodash
import _ from 'lodash';
_.debounce(fn, 300);
// Good — imports only what you need
import debounce from 'lodash/debounce';
debounce(fn, 300);
Dynamic Imports
Not everything needs to load upfront. Load features on demand.
// Load chart library only when the modal opens
const openChart = async () => {
const { Chart } = await import('chart.js');
// ...
};
In Next.js, next/dynamic enables component-level code splitting.
Server Response Optimization
Client-side optimizations hit a ceiling if the server is slow.
Reducing TTFB
Time to First Byte — how long the server takes to start responding. Under 800ms is acceptable, under 200ms is excellent.
- Use a CDN. Serve from edge servers close to your users. Cloudflare, AWS CloudFront, Vercel Edge.
- Server-side caching. Don't hit the database on every request. Redis, in-memory caches.
- Database optimization. Query tuning, proper indexes, fixing N+1 queries.
Caching Strategy
Cache-Control: public, max-age=31536000, immutable
Static assets (JS, CSS, images) get long-term caching with filename hashes for versioning. HTML gets short caching (max-age=0, must-revalidate) or stale-while-revalidate.
Cache-Control: public, max-age=0, s-maxage=60, stale-while-revalidate=300
This caches at the CDN for 60 seconds, and for 5 minutes after expiry it serves the stale version while refreshing in the background.
Compression
Gzip is the baseline. Brotli compresses 15–20% better and is supported by all modern browsers. Configure it on your server (Nginx, Cloudflare, etc.).
Measurement Tools
Without measuring before and after, you won't know if you actually improved anything.
- Lighthouse — Built into Chrome DevTools. Gives an overall score with actionable suggestions.
- PageSpeed Insights — Uses real user data (CrUX). Shows both lab data and field data side by side.
- WebPageTest — Test across different networks, devices, and regions. The waterfall chart is incredibly useful.
- Chrome DevTools Performance tab — Runtime profiling. Track down what's eating main thread time.
Field data from PageSpeed Insights matters more than Lighthouse scores. Lab tests are synthetic; field data reflects what actual users experience.
Quick Reference Checklist
- LCP under 2.5s
- INP under 200ms
- CLS under 0.1
- Images converted to AVIF/WebP
- LCP image has preload + fetchpriority="high"
- Below-fold images use loading="lazy"
- Responsive images with srcset and sizes
- Bundle analyzed, unnecessary dependencies removed
- Code splitting with dynamic imports
- CDN in place
- Long-term caching for static assets
- Brotli compression enabled
- Web fonts optimized (subset, font-display)
- Third-party scripts deferred
You don't need to tackle everything at once. Run Lighthouse, find the lowest-scoring area, and start there. Just optimizing images properly often produces a dramatic difference on its own.