Techniques for improving website performance
The Short Answer
Website performance optimization spans three areas: reducing what you send (smaller bundles, fewer requests), speeding up delivery (caching, CDNs, compression), and optimizing what the browser does with it (efficient rendering, lazy loading, minimal DOM work). The goal is always the same — get meaningful content on screen as fast as possible and keep interactions responsive.
Reduce What You Send
The fastest request is the one you never make. The second fastest is the smallest one. These techniques reduce the total bytes and number of requests the browser needs to make.
Code splitting and lazy loading
Instead of shipping your entire application in one massive bundle, split it into chunks that load on demand. The user only downloads the code for the page they're viewing. In React, lazy() and Suspense make this straightforward — the component's code is fetched only when it's about to render.
import { lazy, Suspense } from 'react';
// This chunk only loads when the route is visited
const Dashboard = lazy(() => import('./pages/Dashboard'));
const Settings = lazy(() => import('./pages/Settings'));
function App() {
return (
<Suspense fallback={<Spinner />}>
<Routes>
<Route path="/dashboard" element={<Dashboard />} />
<Route path="/settings" element={<Settings />} />
</Routes>
</Suspense>
);
}
Tree shaking
Tree shaking eliminates dead code — functions and modules you import but never actually use. Modern bundlers (webpack, Rollup, esbuild) do this automatically with ES modules. The key is using named imports so the bundler can trace exactly what's used.
// ✅ Tree-shakeable — bundler knows only 'debounce' is used
import { debounce } from 'lodash-es';
// ❌ Not tree-shakeable — imports the entire library
import _ from 'lodash';
Image optimization
Images are often the heaviest assets on a page. Use modern formats (WebP, AVIF), serve responsive sizes via srcset, and lazy-load images below the fold. Next.js <Image> handles all of this automatically.
Speed Up Delivery
Caching
Proper HTTP caching headers let the browser reuse previously downloaded resources without making a network request at all. Static assets with content hashes can be cached indefinitely, while dynamic content uses shorter TTLs or revalidation.
# Static assets with hash in filename — cache forever
Cache-Control: public, max-age=31536000, immutable
# HTML pages — always revalidate
Cache-Control: no-cache
# API responses — cache for 60 seconds, revalidate after
Cache-Control: public, max-age=60, stale-while-revalidate=300
CDN (Content Delivery Network)
A CDN serves your static assets from edge servers geographically close to the user. Instead of every request traveling to your origin server in one region, the CDN serves cached copies from the nearest point of presence. This dramatically reduces latency for users far from your server.
Compression
Gzip and Brotli compression reduce text-based assets (HTML, CSS, JS, JSON) by 60-80%. Brotli offers better compression ratios than Gzip and is supported by all modern browsers. Most hosting platforms enable this by default.
Optimize Browser Work
Minimize DOM manipulation
Every DOM change can trigger layout recalculation (reflow) and repaint. Batch your DOM updates, use documentFragment for bulk insertions, and avoid reading layout properties (like offsetHeight) between writes — this forces the browser to recalculate layout synchronously.
Virtualization for large lists
If you're rendering 10,000 rows, don't put 10,000 DOM nodes on the page. Virtualization (libraries like react-window or tanstack-virtual) only renders the items currently visible in the viewport — typically 20-50 nodes instead of thousands.
Debounce and throttle event handlers
Scroll, resize, and input events can fire hundreds of times per second. Throttle scroll handlers to run at most every 100ms, and debounce search inputs to wait until the user stops typing. This prevents unnecessary computation and network requests.
Loading Strategy
How and when you load resources has a massive impact on perceived performance. The techniques below control the priority and timing of resource loading to get critical content on screen first.
| Technique | What it does | Use for |
|---|---|---|
| preload | Fetches resource early with high priority | Critical fonts, hero images, above-fold CSS |
| prefetch | Fetches resource at low priority for future navigation | Next page's JS bundle, likely navigation targets |
| async (script) | Downloads in parallel, executes immediately when ready | Analytics, third-party scripts that don't depend on DOM |
| defer (script) | Downloads in parallel, executes after HTML parsing | App scripts that need the full DOM |
| loading="lazy" | Defers image/iframe loading until near viewport | Below-fold images, embedded videos |
Measuring Performance
You can't optimize what you don't measure. Core Web Vitals are Google's metrics for user experience, and they directly impact search rankings.
- LCP (Largest Contentful Paint) — under 2.5s
- How fast the main content appears
- Optimize: preload hero image, inline critical CSS, fast server response
- INP (Interaction to Next Paint) — under 200ms
- How responsive the page feels to user input
- Optimize: break long tasks, reduce JS execution time, use web workers
- CLS (Cumulative Layout Shift) — under 0.1
- How much the page jumps around during load
- Optimize: set explicit dimensions on images/ads, avoid injecting content above existing content
Why Interviewers Ask This
Performance directly impacts user experience, conversion rates, and SEO. Interviewers ask this to gauge whether you think about performance proactively, know the common bottlenecks and their solutions, and can prioritize optimizations based on impact. They want to see a structured mental model — not just a random list of tricks, but an understanding of where time is spent and how to reduce it at each stage.
Quick Revision Cheat Sheet
Reduce payload: Code splitting, tree shaking, image optimization, compression
Speed delivery: CDN, HTTP caching, preload/prefetch critical resources
Optimize rendering: Virtualization, debounce/throttle, minimize reflows
Loading strategy: async/defer scripts, lazy load images, preload critical assets
Measure: Core Web Vitals — LCP < 2.5s, INP < 200ms, CLS < 0.1