What Happens Between Typing a URL and Seeing the Page
A deep dive into the journey of a single URL — URL parsing, DNS resolution, TCP/TLS handshakes, HTTP requests, server processing, and browser rendering — with a full timing breakdown.
🎯 The Question Every Interviewer Loves
“What happens when you type
https://example.cominto your browser and press Enter?”
This question endures because it touches every layer of the networking stack — application, transport, network, link, and physical. A complete answer touches on 8 distinct phases. Here they are, from keystroke to pixels.
1️⃣ URL Parsing and HSTS Check
Before anything leaves your machine, the browser parses the URL into its components:
| Component | Value |
|---|---|
| Protocol | https |
| Hostname | example.com |
| Port | 443 (implied by HTTPS) |
| Path | / (default) |
| Fragment | none |
The browser then checks its HSTS (HTTP Strict Transport Security) preload list. If the domain is found, the browser refuses to make an insecure HTTP connection — it upgrades directly to HTTPS. This prevents SSL-stripping attacks even on the first request.
If the domain is not preloaded, the browser sends a plain HTTP request first and relies on the server’s Strict-Transport-Security response header to remember the upgrade for future visits.
2️⃣ DNS Resolution
The browser needs the server’s IP address. It checks a chain of caches:
Browser cache → OS cache → Router cache → ISP DNS → Recursive resolver
If none of the caches have the mapping, the recursive resolver (usually your ISP’s or Cloudflare’s 1.1.1.1) begins the lookup:
- Root nameserver — tells the resolver where the
.comTLD nameservers are - TLD nameserver — tells the resolver where
example.com’s authoritative nameservers are - Authoritative nameserver — returns the actual A (IPv4) or AAAA (IPv6) record
Browser Resolver Root (.com) TLD Authoritative
│ │ │ │
│── query: ──────► │ │ │
│ example.com │── where's ──► │ │
│ │ .com? │ │
│ │◄── go ask ────│ │
│ │ TLD → │ │
│ │── where's ──────────────► │
│ │ example? │ │
│ │◄────────── 93.184.216.34 ─│
│◄── 93.184.216.34─│ │ │
Typical timing: 20–50ms for a cold cache, <1ms for a warm cache.
🔧 Modern DNS Optimizations
- DNS prefetching: Browsers eagerly resolve domain names found in
<a>tags before the user clicks - DNS-over-HTTPS (DoH): Encrypts DNS queries to prevent snooping (used by Firefox, Chrome)
- DNS-over-TLS (DoT): Alternative encrypted DNS, preferred by Android
3️⃣ TCP Handshake
With the IP address known, the browser opens a TCP connection to port 443. TCP provides reliable, ordered delivery over an unreliable IP network. The three-way handshake establishes a connection:
Client Server
│ │
│────── SYN ──────────────► │ Client: "Hey, let's talk"
│ │
│◄───── SYN-ACK ────────── │ Server: "OK, I'm ready. You?"
│ │
│────── ACK ──────────────► │ Client: "Confirmed."
│ │
Each unacknowledged segment triggers a retransmission, and the round-trip time (RTT) determines the minimum latency. On a 30ms RTT connection, the TCP handshake alone takes 60ms (one round trip for SYN → SYN-ACK, then ACK is the second).
TCP Fast Open (TFO) eliminates this on repeat connections by sending data inside the SYN packet, saving one RTT. Adoption is limited (~10% of servers).
4️⃣ TLS 1.3 Handshake
Plain TCP gets you a raw pipe, but you need encryption. TLS 1.3 (RFC 8446) reduced the handshake from 2 RTTs (TLS 1.2) to 1 RTT for fresh connections and 0 RTT for resumed ones.
Client Server
│ │
│── ClientHello ──────────► │ Key share, supported ciphers, random nonce
│ (public key share) │
│ │
│◄── ServerHello ──────────│ Cipher choice, server cert + signature
│ + Cert + Finished │
│ │
│── Finished ─────────────►│ Client verifies cert, sends Finished
│ │
│◄════ Encrypted Data ═══► │ Application data begins immediately
Certificate Verification
The browser checks:
- Certificate chain — Is the cert signed by a trusted CA?
- Hostname match — Does the cert’s Common Name or SAN match
example.com? - Expiry — Is the cert still valid?
- Revocation — Is the cert revoked? (via OCSP stapling, not CRL — OCSP is faster)
Typical timing: 1–2 RTT + certificate validation (~50–200ms total). With TLS 1.3 0-RTT resumption, returning visitors skip the handshake entirely.
5️⃣ HTTP Request
With a secure channel established, the browser sends an HTTP request:
GET / HTTP/1.1
Host: example.com
Accept: text/html,application/xhtml+xml,...
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
HTTP/1.1 vs HTTP/2 vs HTTP/3
| Feature | HTTP/1.1 | HTTP/2 | HTTP/3 |
|---|---|---|---|
| Transport | TCP | TCP | QUIC (UDP) |
| Multiplexing | ❌ (6 connections) | ✅ (streams) | ✅ (streams) |
| HOL blocking | Request-level | TCP-level | ❌ None |
| Header compression | ❌ | HPACK | QPACK |
| Server push | ❌ | ✅ | ✅ |
| Connection migration | ❌ | ❌ | ✅ |
| 0-RTT | ❌ | ❌ | ✅ |
HTTP/1.1: One request per connection, limited to ~6 parallel connections per domain. Head-of-line blocking means one slow response blocks everything behind it.
HTTP/2: Multiplexes multiple streams over a single TCP connection. But TCP-level HOL blocking remains — if a single TCP packet is lost, all streams wait for the retransmission.
HTTP/3: Built on QUIC (RFC 9000), which runs over UDP. Each stream is truly independent. A lost packet only blocks its own stream. Connection migration lets you switch from Wi-Fi to cellular without dropping the connection.
Adoption as of mid-2026: HTTP/2 ~65%, HTTP/3 ~35%, HTTP/1.1 ~5% (mostly legacy).
6️⃣ Server Processing
The request arrives at the server. In a modern architecture, it passes through multiple layers:
Client
│
▼
CDN (Cloudflare / Fastly / Akamai)
│ ┌─ Cached static assets served here
▼
Load Balancer (Nginx / HAProxy / AWS ALB)
│ ┌─ TLS termination, routing, health checks
▼
Application Server (Nginx + uWSGI / Node.js / FastAPI)
│ ┌─ Session middleware, auth, business logic
▼
Application Code
│ ┌─ Template rendering, API calls, auth checks
▼
Database (PostgreSQL / Redis / Memcached)
│ ┌─ Query execution, cache lookup
▼
Response (the other way back)
CDN Caching
If the CDN has a cached copy of the response (common for static assets like CSS, JS, images), the request never reaches the origin server. CDN cache hits typically take 5–20ms; cache misses add 200–500ms for origin processing.
Server-Side Timing Breakdown
| Phase | Typical Time |
|---|---|
| TLS termination (LB) | 1–5ms |
| Request routing | 0.1–1ms |
| Auth/session lookup | 5–20ms |
| Application logic | 20–200ms |
| Database queries | 5–100ms |
| Response serialization | 1–10ms |
| Total server time | 50–500ms |
7️⃣ Parsing HTML, CSS, and JavaScript
The browser receives the response — typically an HTML document. Parsing begins immediately, even before the full response arrives (streaming parser).
Bytes → Characters → Tokens → Nodes → DOM Tree
The Parse Pipeline
- HTML parsing — Converts bytes to DOM nodes. When the parser encounters
<script>tags (withoutasyncordefer), parsing blocks until the script is fetched and executed. - CSS parsing — CSS is render-blocking. The browser won’t render anything until the CSSOM is built. Inline CSS is free; external stylesheets block the first paint.
- JavaScript execution — JS can modify the DOM (via
document.write) and the CSSOM (viaCSSStyleSheet), so the parser must wait.
Preload Scanner
Modern browsers deploy a preload scanner — a secondary parser that skims the raw bytes for resource URLs (images, scripts, stylesheets, fonts) and kicks off fetches in parallel before the main parser reaches them. This is why putting <link rel="preload"> or <link rel="preconnect"> in the <head> can dramatically improve load times.
8️⃣ Rendering: DOM → CSSOM → Render Tree → Layout → Paint → Compositing
This is where the page actually appears on screen. The rendering pipeline runs in the browser’s main thread (the “critical rendering path”):
Input: DOM Tree + CSSOM
│
▼
1. Render Tree Construction
│ ┌─ Combine DOM + CSSOM
│ └─ Include only visible elements (no display:none)
▼
2. Layout (Reflow)
│ ┌─ Calculate geometry: position, width, height
│ └─ Every element's box model is computed
▼
3. Paint (Rasterization)
│ ┌─ Fill pixels: colors, borders, shadows, text
│ └─ Layers are painted independently
▼
4. Compositing
│ ┌─ Combine painted layers into final image
│ └─ GPU-accelerated via compositor thread
▼
Output: Screen pixels
Layout Thrashing
Every time you read a layout property (offsetHeight, getBoundingClientRect()) and then write a style change in the same frame, the browser must recalculate layout synchronously. This is called “layout thrashing” and is a common cause of jank.
// Bad — forces synchronous layout twice
const height = element.offsetHeight;
element.style.height = `${height + 10}px`;
element.style.width = `${element.offsetWidth + 10}px`;
// Good — batch reads then writes
const height = element.offsetHeight;
const width = element.offsetWidth;
element.style.height = `${height + 10}px`;
element.style.width = `${width + 10}px`;
Compositor-Only Properties
Modern browsers can animate transform and opacity entirely on the compositor thread, bypassing layout and paint entirely. This is why will-change: transform is the go-to performance hint for animations.
📊 Full Timing Breakdown
Here’s where the milliseconds go for a typical page load with a cold cache:
| Phase | Typical Time | % of Total |
|---|---|---|
| DNS resolution | 20–50ms | 2–5% |
| TCP handshake | 30–100ms (1 RTT) | 3–10% |
| TLS 1.3 handshake | 30–100ms (1 RTT) | 3–10% |
| HTTP request (latency) | 30–100ms (1 RTT) | 3–10% |
| Server processing | 100–500ms | 15–50% |
| HTML parsing + CSSOM | 50–200ms | 5–20% |
| Render tree + layout | 30–100ms | 3–10% |
| Paint + composite | 16–50ms | 2–5% |
| Total | 500ms–2s | 100% |
With a warm cache (repeat visit, CDN cache hit, TLS 0-RTT), the same page loads in 100–400ms.
💡 Key Takeaways
- DNS is the hidden bottleneck — a cold DNS lookup can add 50+ms that most users notice
- TLS 1.3 is a huge win — 1 RTT instead of 2, plus 0-RTT for repeat visitors
- HTTP/3 eliminates HOL blocking — UDP + QUIC means one lost packet doesn’t stall everything
- CDNs matter more than you think — moving content geographically closer to users cuts latency by 50–200ms
- The render pipeline is fragile — layout thrashing from bad JS can undo all the network gains
- Every millisecond counts — Amazon found that every 100ms of latency costs 1% in revenue
The beauty of this question is that there’s always more depth. You can drill into congestion control, into the V8 parser, into the GPU compositor. The layers keep unfolding.