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¶
- sources/2026-05-14-github-from-latency-to-instant-modernizing-github-issues-navigation-performance — canonical wiki instance. Three-way hard / turbo / soft taxonomy with measured share + HPC; in-flight Rails ↔ React migration named as the structural reason hard navigations dominate; rewrite addresses all three classes via shared client-cache substrate plus service-worker intercept.
Related¶
- concepts/highest-priority-content-hpc — the per-class metric whose distribution-by-class makes navigation-mix segmentation legible.
- concepts/distribution-quality-vs-p99-tail — the measurement-philosophy axis that pairs with navigation-mix segmentation (you have to know the mix to know which bucket to fix).
- concepts/react-hydration — the cost component that hard navigations pay and soft navigations don't.
- concepts/streaming-ssr — the SSR shape Turbo navigations remain dependent on.
- concepts/user-perceived-latency — what users actually experience; varies by navigation class.
- systems/hotwire-turbo — the substrate behind Turbo navigations.
- systems/react — the runtime behind soft navigations.
- systems/github-issues-show — canonical wiki instance.