← All writing
Performance

The Engineer's Guide to Web Performance

Performance is a feature you can measure, and most of the wins are unglamorous. Ship less, ship it later, and stop blocking the main thread.

Performance work has a reputation for being deep, arcane, and best left to specialists. In practice, the majority of real-world speed comes from three boring principles applied relentlessly: send less code, send it later, and never block the thread the user is interacting with. Master those and you are ahead of most production sites on the web.

Ship less→ Ship it later→ Free the main thread→ Fast on real devices
The three moves of web performance — send less code, defer everything that is not the first impression, and never block the thread the user is touching.

The cheapest byte is the one you never send

Before optimising what you ship, question whether you need to ship it at all. The largest performance regressions I have fixed were never clever — they were a 400KB date library imported for one function, an icon set pulled in whole for three glyphs, or a hero image served at 4000px on a phone. Audit your bundle, drop what does not earn its weight, and serve images in modern formats at the size they actually render.

Optimisation is mostly subtraction. The fastest code is the code that does not run.

Defer everything that is not the first impression

Your user judges the page in the first second, and they are looking at a small part of it. Everything outside that first impression can wait. Code-split by route, lazy-load below-the-fold images and components, and stream content so the page is useful before it is complete.

  • Split on routes and interactions so the initial bundle stays lean.
  • Lazy-load offscreen media with native loading="lazy".
  • Preload only the critical few — fonts and the hero, nothing else.

Protect the main thread

JavaScript and the user share one thread, and whoever holds it wins. A long task — parsing a huge payload, running an expensive layout — freezes scroll, taps, and typing. Break large work into chunks, move heavy computation to a Web Worker, and be ruthless about what runs during load. Smoothness is not a luxury; jank is the most felt performance bug there is.

// yield back to the browser between chunks
async function processInChunks(items, work) {
  for (let i = 0; i < items.length; i++) {
    work(items[i]);
    if (i % 50 === 0) await new Promise(r => setTimeout(r));
  }
}

Measure on the device your users actually hold

Your laptop on office wifi is a lie. Real users are on mid-range phones and unreliable networks. Test there, watch Core Web Vitals from the field rather than the lab, and set a performance budget so regressions fail loudly in CI instead of slipping in unnoticed.

None of this is magic. It is the same three moves, applied every sprint, until fast is the default state of your product rather than a quarterly cleanup.

Keep reading