Skip to content

CONCEPT Cited by 1 source

Navigation mix

Definition

Navigation mix is the measured distribution of navigation classes reaching a given route in a web application — typically taxonomised as hard / partial / soft with cost shapes that differ by an order of magnitude or more. It is the perf-baselining unit for a multi-class client architecture: you cannot meaningfully optimise the average HPC of a route without first segmenting it by which navigation class produced it.

GitHub's canonical three-way taxonomy from the 2026-05-14 issues#show rewrite (Source: sources/2026-05-14-github-from-latency-to-instant-modernizing-github-issues-navigation-performance):

Class Definition Cost shape
Hard full browser load (cold start, refresh, new tab, direct URL, inbound link) network + server rendering + asset loading + JS boot + React hydration
Turbo (or partial / fragment) a Rails Turbo (or analogous) transition that updates targeted page regions without a full reload server response time still dominant; no JS boot, no full hydration
Soft (React / SPA) client-side transition inside an existing JS runtime data-fetch latency + in-page rendering; no boot, no SSR

Why measuring the mix matters

GitHub's pre-rewrite measured distribution at the start of the workstream:

Class Share HPC median
Hard 57.6 % 2.05 s
Turbo (~5 %) 1.76 s
Soft 37.5 % 1.04 s

"That distribution made one thing obvious: the dominant path was also the slowest. Any strategy focused only on React soft navigations could improve part of the experience, but it could not move overall perceived performance enough on its own."

Without the per-class breakdown, a team optimising the "fast path" (soft navs) would see modest gains in the average HPC — but the majority of users would never feel the improvement, because they were on a different navigation class. The measured navigation mix is what tells you where to invest.

Cost composition by class

What each class actually pays:

  • Hard navigation — DNS, TLS, TCP, HTTP request → server routes the request → server renders HTML → streaming SSR flushes bytes → browser parses HTML → asset loading (CSS, JS) → JS parse + evaluate → React mount + hydration → first content render. The whole stack.
  • Turbo navigation — XHR-style fetch for a fragment → server still runs application code to compute the fragment → server-rendered HTML returned → DOM swap. JS runtime is already alive; no boot, no full hydration. Server-bound.
  • Soft navigation (React) — already-mounted React runtime initiates a data fetch for the new route's payload, renders in place. No server-rendering on the critical path; no boot; no hydration. Data-fetch-bound (or, with a client cache, memory-read-bound).

What changes the mix

The most important driver in GitHub's case was the frontend migration itself: GitHub is moving from Rails-rendered pages to a React frontend, and "during that transition, many user journeys cross the Rails/React boundary. When that happens — for example, navigating from a Rails page into Issues — the browser often has to do a full hard navigation and cold boot. That boundary crossing is a big reason hard navigations made up the largest share of our baseline." The expectation is that "share of hard navigations to decrease over time as more surfaces become React-native."

Other things that shift the mix:

  • Bookmarks / direct URLs / inbound links can never be soft — they're all hard navigations.
  • Refresh / new tab are hard navigations.
  • In-app links between same-frontend surfaces can be soft if the runtime is unified.

Architectural implications

The taxonomy is not just descriptive — it shapes what optimisations are feasible:

  • Soft navigations are the highest-leverage starting point because the runtime is already alive and the dominant cost is data fetch. Client caches (e.g. on IndexedDB) can move large slices of this traffic from network-bound to memory-bound.
  • Turbo navigations are server-cost-bound; optimisations that let the server skip work (service-worker cache-hint header is GitHub's instance) help most.
  • Hard navigations can't be made fully instant — they always pay the cold-boot tax — but a well-designed service worker can intercept the request, signal the server that local cache exists, and let the server return a thin shell instead of a full SSR payload.

The cleanest design is one where the same client cache (populated on soft navs, persisted in IndexedDB) is made available to hard navs via a service worker, so optimisation work amortises across all three classes rather than being duplicated three times.

Seen in

Last updated · 542 distilled / 1,571 read