Skip to content
Chapter 10Lesson 1

URL bar to first byte

Your entry point to how the web works under the hood, the four network stages a request crosses before a page can load, on the 2026 HTTP/3 stack.

A slow page load is rarely one problem. A request crosses four stages between the moment you commit a URL and the moment the first byte comes back, and usually one of those stages is the bottleneck while the other three are fine. An engineer who can look at a single waterfall row and name the slow stage starts debugging in the right place. One who reads “the site is slow” and jumps straight to the server logs can lose half a day checking something that was never the problem.

This lesson maps that route. The four stages are DNS, transport, TLS, and HTTP, named in the 2026 vocabulary, and each one gets a prose section and a labelled spot on a shared diagram. A fifth section covers reading the DevTools Network panel, where you’ll spend most of your debugging time through the rest of this unit. What happens after the first byte arrives, the browser side of the pipeline, is the next lesson. A deeper TLS treatment at debugging depth comes later in this chapter.

Before going further, open DevTools (Cmd+Opt+I on macOS, F12 on Windows or Linux), switch to the Network tab, right-click any column header, and turn on the Protocol column. Leave it open. You’ll use it mid-lesson.

Here’s the whole route a request takes, end to end. Look at it once before reading the prose, since each stage below refers back to this diagram.

%%{init: {'themeCSS': '.messageText, .messageText tspan, .actor, .actor tspan, .noteText, .noteText tspan, .labelText, .labelText tspan { font-size: 18px !important; } .loopText, .loopText tspan { font-size: 16px !important; }'} }%%
sequenceDiagram
    participant B as Browser
    participant R as Resolver
    participant S as Server

    rect rgba(56, 189, 248, 0.12)
        Note over B,S: Stage 1 — DNS · ~20-80 ms cold, ~0 ms warm
        B->>R: query example.com (A + AAAA)
        R-->>B: 2606:4700:: / 104.16....
        Note over B,R: Happy Eyeballs v2 races IPv6 and IPv4
    end

    rect rgba(34, 197, 94, 0.12)
        Note over B,S: Stages 2+3 — Transport + TLS folded into QUIC · 1 RTT fresh, 0 RTT resumed
        B->>S: Initial (ClientHello + QUIC frames)
        S-->>B: ServerHello + cert + handshake
        B->>S: Finished
        Note over B,S: HTTP/3 over QUIC on UDP/443 — TLS 1.3 folded in
    end

    rect rgba(244, 114, 182, 0.12)
        Note over B,S: Stage 4 — HTTP request · TTFB
        B->>S: GET / HTTP/3
        S-->>B: 200 + first byte
    end
Four stages from URL commit to the first byte of HTML on the 2026 default stack — HTTP/3 over QUIC, TLS 1.3, DoH where the resolver supports it.

Read the diagram top to bottom. The horizontal arrows are network round trips. Each one is a real journey between the client and a remote machine, and each one costs wall-clock time. Stages 2 and 3 are drawn together because in 2026 they are physically the same handshake: TLS 1.3 is folded into the QUIC transport setup, so the secure pipe gets built in one round of negotiation rather than two. Stage 4 is the actual HTTP request, the one that carries a method and a path. Stages 1 through 3 are the cost of getting ready to make that request. An experienced engineer debugging a slow page checks those setup stages first, because on a warm connection they collapse to near zero, as the numbers in the next four sections show.

The browser is given a hostname like app.example.com, but the network stack can’t open a connection to a hostname. It needs an IP address, and turning one into the other is what DNS does.

The browser hands the hostname to the OS resolver, and the resolver walks a chain of caches looking for the answer. It checks the browser’s own cache first, then the OS cache, then the recursive resolver your network is configured to use (often your ISP’s, increasingly Cloudflare’s or Google’s), and finally the authoritative server for the domain if nothing along the way had the answer. A cold lookup, with nothing cached anywhere, typically costs 20 to 80 milliseconds. A warm lookup costs effectively zero.

In 2026, that resolver conversation is increasingly encrypted. The standard form is DoH , where the DNS query rides inside an HTTPS connection to a DNS provider that speaks the protocol. Firefox enables DoH by default in most regions, and Chrome and Edge auto-upgrade to it when the system resolver advertises support, falling back to plain DNS otherwise. Plain DNS is the floor the stack drops to when nothing better is available, not the default. Two other encrypted forms exist: DoT (DNS over TLS) is the OS-level alternate, and DoQ (DNS over QUIC) is the QUIC-native one. They’re worth naming so you don’t assume DoH is the only encrypted option, but DoH is the production reality the course assumes.

The browser does something here that most newcomers don’t picture: it doesn’t issue one lookup, it issues two and races them, an A record query for IPv4 and an AAAA query for IPv6. The algorithm is Happy Eyeballs v2 . When both families resolve in time it prefers IPv6, giving it a roughly 50 ms head start, but it never waits on IPv6: if v6 is broken, v4 wins and the user notices nothing. Without this race, a misconfigured IPv6 path would stall the page for the resolver’s full timeout.

Once the browser has an IP address, it needs to open a connection to it. The 2026 default is QUIC on UDP port 443, carrying HTTP/3.

HTTP/2 over TCP solved a real problem, multiplexing several requests on one connection, but it solved it at the HTTP layer. The transport underneath was still TCP, and TCP delivers bytes strictly in order: if one packet drops, every later packet on the connection waits for it, even packets that belong to a different stream. That stall is head-of-line blocking, and on a flaky mobile network it wrecks throughput. QUIC moves multiplexing down into the transport itself, so each stream keeps its own state and a lost packet holds up only the stream it belonged to. It also folds in TLS 1.3 (Stage 3 below) and pushes encryption deeper into the stack, so even the transport metadata is encrypted.

The browser doesn’t gamble on HTTP/3 for a brand-new origin. It opens its first connection over HTTP/2, sees the Alt-Svc response header advertising that HTTP/3 is available, and upgrades on the next request. A newer mechanism, the HTTPS DNS record (type 65 / SVCB), lets a browser learn about HTTP/3 from the DNS lookup itself. That mechanism is growing, but Alt-Svc is still the most common discovery path in 2026. You’ll see the practical consequence in the DevTools drill at the end of this lesson: the very first document request to a fresh origin can show h2, and the second navigation flips to h3. That isn’t a bug, just the browser learning the origin supports HTTP/3.

The fallback path still matters, because HTTP/2 over TCP plus TLS 1.3 is everywhere. Corporate networks sometimes block or throttle UDP, and clients then fall back to HTTP/2 silently. Origins that haven’t moved still serve HTTP/1.1 to clients that handshake it. The course writes no HTTP/1.1-specific code.

The round-trip story is what makes QUIC worth the change. It’s clearest with three cases set side by side.

Client -> Server : Initial + ClientHello + (early HTTP request frames)
Server -> Client : ServerHello + cert + handshake + Finished
Client -> Server : Finished + HTTP request body
(continues...)

One round trip sets up the connection, and the request goes out the moment the handshake completes. No session ticket exists yet, but TLS 1.3 inside QUIC needs only one round trip to establish keys, and the request follows immediately. Latency to the first byte works out to roughly two round trips: one for the handshake, one for the response.

The number to remember: fresh QUIC is 1 RTT, resumed QUIC is 0 RTT, TCP plus TLS is 2 RTT. On a mobile connection where one round trip can be 100 ms or more, that’s the difference between a snappy page and a sluggish one.

Stage 3: TLS 1.3 inside the QUIC handshake

Section titled “Stage 3: TLS 1.3 inside the QUIC handshake”

This section stays short on purpose. The deeper TLS treatment, covering cipher suites, certificate chains, SNI, and ALPN, lives in the HTTPS on localhost lesson later in this chapter, framed against mkcert and local HTTPS. Here, four facts are enough to make sense of the diagram and the RTT counts.

TLS 1.3 is the only flavor the 2026 stack ships. TLS 1.2 is deprecated, and the browser refuses to speak older protocols. Treat it as a given.

In QUIC, TLS is interleaved with the transport handshake. The ClientHello rides inside the very first QUIC packet rather than as a separate step on top. A fresh connection completes in one round trip; a resumed connection completes in zero, using a session ticket the client kept from the previous visit.

0-RTT carries a replay-safety constraint. Early data is the request bytes carried inside the first packet on a resumed connection. Those bytes have no fresh nonce from the server yet, so an attacker who recorded the encrypted packet could replay it later, and the server would have no way to tell the replay apart from the original. The fix is to send only idempotent GETs as early data; non-idempotent requests, meaning POST, PATCH, DELETE, or anything else that changes state on the server, wait for the full handshake. The browser and the HTTP/3 stack handle this for you. The rule is still worth knowing, because the next chapter on the HTTP contract leans heavily on idempotency as the property that makes safe retries possible.

TLS 1.3 always gives normal traffic forward secrecy. Even if the server’s long-term private key leaks tomorrow, recorded sessions from yesterday stay undecryptable, because each session uses its own ephemeral keys. The one exception is 0-RTT early data, which has no forward secrecy: by construction the request rides on keys derived before the new ephemeral exchange. That’s one more reason early data is reserved for idempotent GETs.

The full TLS 1.3 handshake, including cipher-suite negotiation, the ALPN identifiers (h3, h2, http/1.1), SNI (Server Name Indication), and certificate chain validation, is the subject of the HTTPS on localhost lesson later in this chapter. All this section needed was the round-trip count and the resumption story.

Once the secure transport is up, the client finally sends what it came for: an HTTP/3 request. It carries a method (GET), a path (/), a :authority pseudo-header naming the host, the request headers, and, for non-GET requests, a body. The server processes it and starts responding, and the first byte of the response body arrives.

The wall-clock time from the moment the browser commits the URL to the moment that first byte lands is TTFB . It’s a single number on the stopwatch, but it is not a single thing. It bundles every stage above: DNS, connection setup, TLS handshake, request travel, server thinking time, and the network round trip for the response.

TTFB is the metric the performance chapter in Unit 19 tunes against. Here it’s just a label, and the point is that a slow server is only one possible explanation, with three others sitting upstream of it.

You opened DevTools at the top of the lesson. The Network panel is where every later chapter in this unit will send you. Each row in the panel is one request, and each row carries a Protocol label and a Timing breakdown that map directly onto the stages above.

The Protocol column you enabled at the top tells you which version the request used. The three values you’ll see:

  • h3: HTTP/3 over QUIC. The 2026 default.
  • h2: HTTP/2 over TCP + TLS. The fallback, and also the first hit to a fresh origin before Alt-Svc discovery has happened.
  • http/1.1: Legacy. Origins that haven’t moved, or clients on networks that block UDP and fall back past both the HTTP/2 and HTTP/3 hints.

The Alt-Svc nuance from Stage 2 shows up here. On a fresh origin, the very first document request can show h2; reload the page and the document row should flip to h3, because the browser has now learned HTTP/3 is available. If a production origin still isn’t h3 on a second load, that’s a configuration conversation with whoever manages the origin’s CDN, not a bug in your code.

Click a row in the Network panel, switch to the Timing tab, and you’ll see a stacked bar. Each segment is one of the stages this lesson named, and they map straight across:

  • Queued / Stalled : the browser’s own bookkeeping. The request is waiting on a connection slot or a priority queue.
  • DNS Lookup : Stage 1. Often shows 0 ms on warm caches.
  • Initial connection : Stage 2. For h3 requests, the QUIC handshake collapses into this segment. For h2, this is just the TCP handshake.
  • SSL : Stage 3. For h3, it’s folded into Initial connection and often not shown as a separate bar. For h2, it’s the explicit TLS round trip on top of TCP.
  • Request sent: bytes uploaded. Usually tiny for a GET.
  • Waiting (TTFB) : Stage 4. Server thinking time plus the round trip back.
  • Content Download : body bytes streaming in.

That’s the whole vocabulary of the panel. Once you’ve read a few real waterfalls with these labels in mind, every later debugging conversation in this unit lands somewhere on this list.

Now do it on a real site. Follow the steps below against cloudflare.com (always served over h3 on a modern browser) or against this course’s site.

  1. In DevTools, switch to the Network tab. In the toolbar at the top of the panel, tick Disable cache. This forces a real network fetch instead of a cached response.

  2. Hard-reload the page (Cmd+Shift+R on macOS, Ctrl+Shift+R on Windows or Linux). Watch the document row, the very first row, the one for the page’s HTML.

  3. Check the Protocol column. On the first load to a fresh origin you may see h2; do one more reload and the document row should flip to h3, because the browser learned about HTTP/3 from the Alt-Svc header on the first response. Click the document row, open the Timing tab, and find the DNS Lookup, Initial connection, Waiting (TTFB), and Content Download segments. On h3, the SSL bar collapses into Initial connection, which is the transport-plus-TLS fold the diagram showed.

  4. Untick Disable cache and do a soft reload (Cmd+R or F5). The DNS Lookup and Initial connection segments should collapse to near zero. That’s the resumed-connection effect made visible: the DNS is cached and the QUIC connection is still alive.

  5. Click the Waiting (TTFB) segment and read its number. That’s the server-and-network cost in isolation, with all the setup costs already paid in previous requests.

For reference, here’s what an annotated h3 timing breakdown looks like, with each label mapped to its stage from the diagram.

LocalQueuedStalledDNS · 0 msInitial connectionQUIC + TLS foldedReqWaiting (TTFB)Content DownloadStage 1DNS resolution(warm cache)Stages 2 + 3QUIC handshakeTLS 1.3 folded inStage 4HTTP request + server= TTFBResponse bodybytes streaming inOn h3 the SSL bar is folded into Initial connection, so there is no separate TLS row.DNS Lookup is a 0 ms sliver because this row’s resolver hit a warm cache.
A schematic h3 document request Timing panel. Initial connection holds the QUIC + TLS handshake (Stages 2 and 3 folded), and Waiting (TTFB) is Stage 4. DNS Lookup is 0 ms because the lookup hit a warm cache; SSL is folded into Initial connection, so it never appears as its own bar.

The waterfall is where you’ll read the network for the rest of Unit 2. Every fetch you make later in the unit, every cookie you set, and every CORS preflight shows up here as a row you can hover, click, and read. The vocabulary you just learned stays with you: h3 versus h2, the DNS / Initial connection / SSL / Waiting / Content Download segments, and fresh versus resumed connections.

One short drill before closing. The whole point of the four-stage map is to look at any waterfall row and name which stage is the bottleneck, because that’s the move that lets an experienced engineer aim their debugging. Match each row’s shorthand description to the stage that dominates its time.

Match each waterfall row shorthand to the stage that dominates its wall-clock time. Click an item on the left, then its match on the right. Press Check when done.

h3 · DNS 0 ms · Initial connection 0 ms · Waiting (TTFB) 320 ms · Content Download 12 ms
Server-bound — warm connection, the server is thinking
h2 · DNS 75 ms · Initial connection 90 ms · SSL 80 ms · Waiting (TTFB) 60 ms · Content Download 8 ms
Connection-bound — cold TCP + TLS handshake dominates
h3 · Queued 0 ms · DNS 60 ms · Initial connection 35 ms · Waiting (TTFB) 50 ms
DNS-bound — cold lookup dominates
h3 · Queued 280 ms · DNS 0 ms · Initial connection 0 ms · Waiting 40 ms
Queue-bound — browser priority queue or connection-pool stall
h3 · Waiting (TTFB) 30 ms · Content Download 1800 ms
Content-bound — large response body, server was fast
(from disk cache) · 0 ms total
Cached — no network leg at all, served from the browser’s HTTP cache

If you can read these six rows and name the slow stage, you can do it for any row in production. Naming the stage before you start debugging is the skill worth keeping from this lesson. Protocols will turn over and the vocabulary will drift, but the staged mental model survives both.

A few topics belong nearby rather than here. Each is named once so you know where it lands.

The HTTP method, status, and header contract (GET / POST / PUT / PATCH / DELETE, the status-code families, the header categories) is the next chapter’s full territory. Origins and CORS are the chapter after that, and cookies with Secure and SameSite are the one after that. The deeper TLS 1.3 handshake at debugging depth, covering cipher suites, the full certificate chain, SNI, and ALPN, is the HTTPS on localhost lesson later in this chapter, where you’ll wire up https://localhost with mkcert. The browser-side pipeline, what happens after the first byte arrives along the parse-DOM-CSSOM-layout-paint-composite path, is the next lesson.

The first byte is here. In the next lesson, it becomes pixels.