seo

Core Web Vitals in 2026: Why Edge Rendering Beats Most Optimisation

Serving HTML from 300+ locations usually beats weeks of JavaScript micro-optimisation. Here is how to measure the difference properly.

There is a recurring pattern in performance work. A team spends three weeks reducing their JavaScript bundle by 38 percent, ships it, and their Largest Contentful Paint barely moves on mobile. The reason is almost always that they optimised the code and ignored the delivery.

What LCP actually measures

Largest Contentful Paint is the render time of the largest image or text block in the viewport. Four sequential phases have to complete:

  1. Time to first byte - the server receives the request and starts responding.
  2. Resource load delay - the browser discovers the LCP element in the HTML.
  3. Resource load duration - the element downloads.
  4. Element render delay - everything required to paint it has arrived.

JavaScript reduction attacks phase 4 - and only if JavaScript is actually blocking that paint. On a text-heavy content site it often is not. What dominates is phase 1.

The arithmetic of a real round trip

Consider a content site with a 180 millisecond time to first byte from a single origin in Virginia.

User locationNetwork RTTTTFBLCP (typical)
Virginia, US8 ms180 ms1.1 s
Berlin, DE95 ms290 ms2.0 s
São Paulo, BR130 ms330 ms2.4 s
Mumbai, IN210 ms420 ms3.3 s
Jakarta, ID240 ms460 ms3.8 s

The fieldwork result that matters: Core Web Vitals are assessed at the 75th percentile of your actual traffic. If a third of your readers are in South and Southeast Asia, your origin in Virginia is the bottleneck, and it is not a JavaScript problem.

Why edge rendering changes the number

When HTML is generated or cached at an edge location within tens of milliseconds of the reader, phase 1 collapses:

User locationEdge TTFBLCP (typical)Change
Virginia, US12 ms0.9 s-0.2 s
Berlin, DE18 ms1.1 s-0.9 s
São Paulo, BR22 ms1.2 s-1.2 s
Mumbai, IN30 ms1.5 s-1.8 s
Jakarta, ID34 ms1.7 s-2.1 s

Same application, same content, same assets. The only change is where the response is assembled.

Static-first is the version that actually holds

There is a hierarchy of delivery strategies, ordered by how reliably they hit the target:

Static assets on a CDN. Every page is a file. Fastest and most predictable. Requires a build step and a redeploy for content changes.

Edge-rendered with a shared cache. The route runs at the edge, but the cache key is shared across all users, so most requests never execute application logic. Nearly as fast as static, and dynamic content works.

Edge-rendered per user. The route executes within the reader's region. Removes the transcontinental trip, but application logic still runs. Fine for personalisation, not for a marketing page.

Origin-rendered. Everything is computed in one place. Correct, and the slowest option for a distributed audience.

Most content sites should be a mix: static for marketing and article pages, edge-rendered with shared caching for anything that reads from a database, and per-user rendering only inside authenticated areas.

Implementing shared-cache edge rendering

The mechanism is smaller than the terminology suggests. In a Cloudflare Workers environment:


export async function onRequestGet({ request, env, waitUntil }) {
  const cache = caches.default;
  const cacheKey = new Request(new URL(request.url).toString(), request);

  let res = await cache.match(cacheKey);
  if (!res) {
    const rows = await env.DB
      .prepare('SELECT ... FROM websites WHERE status = ? ORDER BY score DESC LIMIT 20')
      .bind('approved').all();

    res = new Response(renderHtml(rows.results), {
      headers: {
        'content-type': 'text/html; charset=utf-8',
        'cache-control': 'public, s-maxage=60, stale-while-revalidate=600',
      },
    });
    waitUntil(cache.put(cacheKey, res.clone()));
  }
  return res;
}

Three details carry the performance:

  • s-maxage=60 keeps the shared cache warm for a minute. The homepage query runs at most once per minute per location, not once per visitor.
  • stale-while-revalidate=600 lets the edge serve a slightly stale copy while refreshing behind the request. Readers never wait for the refresh.
  • waitUntil writes the cache entry without blocking the response.

Stale data is a product decision, not a technical one

A cached leaderboard is sixty seconds out of date. For a toplist of websites, nobody has ever noticed. For a member's own credit balance, sixty seconds is unacceptable and the route should skip the cache entirely and read from the database.

The rule: anything a user compares against their own recent action must bypass the cache. Anything that represents the state of the world can be cached. A leaderboard is the state of the world. A dashboard is not.

Measuring properly

Lab tools use a simulated device on a fast connection. Real users are on mid-range Android over cellular. Both are worth looking at, and they disagree.

  • lab tools for regression detection in CI, where you control the variables.
  • real user monitoring for understanding the distribution, because the 75th percentile is the metric that counts.
  • Network throttling on a mid-tier device for anything you intend to claim publicly. If the number is only good on your laptop, it is not good.

Watch out for a common trap: adding heavy client-side analytics to measure performance can itself degrade performance. Load measurement after the load event, keep the payload under 5 kB, and never let it block rendering.

The order of operations

  1. Put HTML on the edge. This is the largest single win available and it is usually an afternoon of work.
  2. Compress and correctly dimension the LCP image. Preload it if it is the hero.
  3. Set explicit dimensions on all media to eliminate layout shift.
  4. Reduce render-blocking CSS and defer non-critical JavaScript.
  5. Only now consider shaving kilobytes off the bundle.

Teams consistently do these in reverse. Doing them in order means the first step alone often gets you to the target, and the last step becomes optional rather than urgent.

Continue reading