Generate a follow-up sub-lesson on any aspect of this topic
Guide complete
What Happens When a Web Page Loads
Generate a follow-up sub-lesson on any aspect of this topic
What Happens When a Web Page Loads
TLDR;
- A single page load often waits on several full network round trips before any pixels appear.
- A DNS cache miss can delay everything else because no connection can start without an IP address.
- One slow backend dependency can dominate total time even when the network is fast.
Type a URL on coffee shop Wi Fi and the main thing to notice is that the browser cannot jump straight to content. A page load is a chain of dependent steps, and many of them require a full round trip which is one message out and one message back before the next step can begin. If the Wi Fi adds of round trip time, then each required handshake or lookup tends to cost about even before downloading the page body. To keep the mental model simple, start with one browser talking to one origin server over plain http:// with no encryption and no redirects, then add the extra layers one by one. Let’s ground the full lifecycle path we are about to walk through:
That diagram is the whole story in one line. The browser must learn an IP address through DNS, establish a transport connection with TCP, optionally establish trust and encryption with TLS, send an HTTP request, wait for server work, receive an HTTP response, then parse and render which triggers more fetching. The reason one slow hop dominates is dependency order. The browser cannot start TCP before DNS, and it cannot safely treat bytes as an HTTP response before any required TLS handshake completes.
The web runs on a client server model where the browser is the client that initiates work and the web server is the server that waits for requests and returns responses. Each navigation turns into one or more HTTP transactions, and the baseline unit is a single request which is the message the client sends to ask for a resource, followed by a response which is what the server returns with a status code, headers, and a body. When people call HTTP stateless, they mean the server does not have to remember prior requests to understand the current one, so the browser must attach context each time using headers and cookies. Here is what sits where for one page request:
The key distinction in that breakdown is where state lives. The browser stores history, cached responses, and cookies, while the server stores application data in its own storage and reads any per user context from each request. If the browser does not send a Cookie header or an Authorization header, the server usually has no other way to associate the request with a logged in session, even if the same TCP connection is reused.
Before a browser can open a connection, it needs an IP address, and DNS is the system that maps a human readable name like www.example.com to an address like 203.0.113.10. A DNS lookup is often invisible when caches hit, but on a cache miss the browser asks a recursive resolver, which then asks authoritative name servers, and the browser must wait for the answer before it can even attempt TCP. That is why DNS shows up as a separate round trip in page load waterfalls. The cache chain looks like this in practice:
What changed between a hit and a miss is not just time, it is ordering. With a warm browser or OS cache, the browser moves immediately to TCP. With a cold cache, the recursive resolver has to do extra work on the browser’s behalf, and the browser is blocked until the resolver returns an IP and a TTL that tells caches how long they may reuse it.
Design rule
When step B needs the output of step A, speeding up B never fixes A’s miss.
Once the browser has an IP address, it usually uses TCP, which is a reliable transport that delivers bytes in order and retransmits lost packets. Reliability is not free. Before any HTTP bytes flow, TCP performs a three way handshake so both sides agree on sequence numbers and both directions are reachable. That handshake costs one round trip, and on high latency links it can be a large fraction of the time to first byte. The handshake sequence is small but strictly ordered:
The diagram highlights why people care about connection reuse. If the browser can reuse an existing TCP connection, it avoids paying that extra round trip again. If it cannot reuse, the handshake delay is paid up front and any packet loss during startup can also reduce initial throughput because TCP congestion control begins cautiously and ramps up as acknowledgements arrive.
If the URL is https://, the browser layers TLS on top of TCP to get confidentiality and server authentication. TLS is a secure channel that encrypts traffic and also verifies that the server is the one the browser intended to reach. The server proves its identity using a certificate, and the browser verifies that certificate against trust anchors it already has. This handshake typically adds more back and forth before the browser treats any HTTP response bytes as trusted. The minimal flow looks like this:
The important behavior change with TLS is that the browser does not just need reachability, it needs proof. The browser waits for the server certificate, checks names, validity, and signatures, then derives session keys. Until that completes, an attacker on the coffee shop Wi Fi cannot be allowed to inject or read content, so the browser intentionally delays processing until the handshake finishes.
With a connection ready, HTTP finally expresses intent. The browser sends a method like GET for a document, a path like /, and headers that describe what it accepts and what it already has cached. The server answers with a status code that drives control flow. A 200 includes the content, a 301 tells the browser to go somewhere else which adds another request, and a 304 tells the browser it can reuse a cached copy which saves bytes. Small server decisions like adding cache headers can remove whole downloads, while redirects can add whole round trips. Compare the common outcomes for the same URL:
After the widget, the main difference to watch is how many transactions happen before the browser can render. A 301 usually forces a second full request response pair, and if that second URL is on a different hostname it can also force extra DNS, TCP, and TLS work. A 304 still costs a round trip but avoids transferring the body, which often helps on slow links but still blocks on latency.
The server side path often looks simple from the outside, but a single request can fan into multiple internal calls. A load balancer picks a healthy instance, the application runs logic, and then it often needs data from a cache or database. The user experiences the slowest part of this chain because the server cannot respond until all required dependencies return or time out. This is where tail latency matters, which is the slow end of the latency distribution that users notice as occasional slowness. Here is the core tradeoff when serving a page from cache versus computing it and reading the database:
The decision matrix usually pivots on freshness versus speed. A cache hit can return in a few milliseconds but risks serving slightly stale content depending on the invalidation policy, while a database read gives the latest committed data but can be slower and can fail under load. When the database is replicated, consistency can also depend on which replica serves the read. A follower replica can lag the leader, and a quorum read trades latency for stronger guarantees.
Practical caveat
If one dependency has a chance of taking , users will remember the .
The first HTML response is rarely the whole page. The browser parses HTML into a DOM, discovers subresources like CSS, JavaScript, and images, and then schedules additional fetches. Each additional hostname can require its own DNS and connection setup, and each additional request can contend for limited parallel connections. The browser also blocks rendering on some resources. For example, CSS can block first paint because styles affect layout. This is why performance work often focuses on reducing critical requests and making early bytes useful. The tradeoff between fewer large resources and many small ones looks like this:
After the widget, the key is that the browser is doing two jobs at once. It is a network client that tries to fetch efficiently, and it is a renderer that tries to build a stable layout without redoing work. Many small files can waste time on extra round trips and request overhead, while a few large files can delay the first meaningful render if nothing can be shown until a big download finishes. Modern protocols reduce some overhead, but the dependency graph still decides what the user sees first.
A useful way to explain page load time is to point at what must happen in order, and what can happen in parallel. The ordered backbone is name resolution, connection establishment, request, server work, response, then parse and render. The parallel part is subresource fetching once the browser has enough HTML to discover them. Latency is the time something takes end to end, and it is often dominated by the count of required round trips rather than raw bandwidth. When debugging slowness, the first question is which step is waiting on another step, because that is the constraint that sets the lower bound.
This mental model holds until the assumptions change. If the page moves to https:// you add TLS work. If the site adds redirects, you add more transactions. If the backend adds more dependencies, the slowest one starts to dominate. The redesign trigger is always the same. When the page’s dependency chain gets longer than the latency budget users tolerate, the only durable fix is to remove required round trips or remove required waits by caching, preconnecting, or changing what must be fetched before first render.