Most web developers use HTTP every day.
We write fetch(), call APIs, send requests, and handle responses. But lets understand what happens underneath those familiar abstractions.
When we write:
const response = await fetch("https://api.example.com/users");
how does that request reach another computer? What happens before the server receives it? And why can a request be slow even when the application code is fast?
Here's what I've been learning.
The layers underneath HTTP
A simplified view of networking looks like this:
Application
↓
HTTP
↓
TCP
↓
IP
↓
Ethernet / Wi-Fi
↓
Network
Each layer solves a different problem.
- HTTP defines how applications structure requests and responses.
- TCP provides a reliable, ordered byte stream.
- IP helps packets travel between networks.
- Ethernet/Wi-Fi handles communication over a local network link.
The important realization is that HTTP doesn't handle everything. It's one layer in a much larger system.
HTTPS adds TLS to protect HTTP traffic, typically over TCP. HTTP/3 is different: it runs over QUIC, which uses UDP.
IP addresses and ports
An IP address helps identify the network destination. A port identifies the transport endpoint associated with an application.
For example:
Server: 203.0.113.10
Port 22 → SSH
Port 443 → HTTPS
Port 5432 → PostgreSQL
A few addresses worth understanding:
-
127.0.0.1— IPv4 loopback, referring to the local machine. -
192.168.x.xand10.x.x.x— private IPv4 address ranges. -
0.0.0.0— when used as a listening address, commonly means listening on all local IPv4 interfaces.
This last one is particularly useful in backend development. A server bound to 127.0.0.1 generally won't accept connections from other machines through its LAN interface, whereas binding to 0.0.0.0 allows it to listen on all local IPv4 interfaces, subject to firewall and network rules.
Routers forward packets between networks, while NAT often allows multiple devices with private addresses to share a public IPv4 address.
TCP: Reliable communication
IP alone doesn't guarantee that packets arrive or arrive in order. TCP provides reliability on top of IP.
A TCP connection typically begins with a three-way handshake:
Client Server
SYN ────────────────>
<────────── SYN + ACK
ACK ────────────────>
After establishing the connection, TCP uses sequence numbers, acknowledgements, and retransmissions to deliver an ordered stream of bytes.
It also uses:
- Flow control to avoid overwhelming the receiver.
- Congestion control to respond to network congestion.
- Connection termination to close connections safely.
One important concept:
TCP gives you a reliable byte stream, not messages.
If an application sends HELLO and WORLD, the receiver isn't guaranteed to receive them as two separate chunks. It might read HELLOWORLD, or several smaller pieces.
TCP preserves byte order, not application-level message boundaries. Protocols such as HTTP define their own message structure.
DNS: From domain name to IP address
Humans use names like google.com, but network connections need an IP address.
DNS resolves domain names into records, including IP addresses.
google.com
↓
DNS resolver
↓
IP address
↓
Connection
A recursive resolver may answer from its cache or query the DNS hierarchy to obtain the relevant record.
DNS records have a TTL (Time to Live), which controls how long a record may be cached. This reduces repeated lookup work, but it also explains why DNS changes may not be visible everywhere immediately.
Useful commands to explore this:
dig google.com
dig google.com A
dig google.com AAAA
DNS helps discover the destination; it doesn't establish the connection itself.
HTTPS and TLS
Resolving a domain and establishing a TCP connection aren't enough if we want secure communication.
TLS adds encryption, integrity protection, and server authentication when certificate validation succeeds.
For a typical HTTPS connection over TCP:
DNS resolution
↓
TCP handshake
↓
TLS handshake
↓
HTTP request
↓
HTTP response
This setup has a cost. But connection reuse, caching, and TLS session resumption can reduce repeated work.
HTTP/2 also introduced multiplexing, allowing multiple streams to share a TCP connection. HTTP/3 uses QUIC over UDP, providing independent streams that reduce the cross-stream blocking caused by TCP packet loss.
The HTTP methods and status codes remain familiar; the underlying transport has evolved.
What actually happens when we call fetch()?
Putting everything together, a simplified request lifecycle looks like this:
fetch("https://api.example.com/users")
↓
DNS resolution
↓
TCP connection
↓
TLS handshake
↓
HTTP request
↓
Network → Server
↓
Application processing
↓
HTTP response
↓
Client receives it
This is a conceptual sequence. Existing DNS entries and reusable connections can skip some setup steps, and HTTP/3 follows a different connection-establishment path.
The server might also query a database or call other services before returning the response.
Latency isn't just server execution time
Suppose an API request takes 800 ms, but the server spends only 30 ms executing application code.
Where did the rest go?
Potentially:
- DNS lookup
- Connection establishment
- TLS handshake
- Network round trips
- Packet loss and retransmissions
- Queueing
- Downstream service calls
- Response transfer
This is why total request latency and application execution time are different things.
Understanding the networking layers gives us a better starting point for investigating slow requests instead of immediately blaming the application.
A few things to try
I found it more useful to inspect actual network behavior than to memorize protocol definitions.
curl -v https://example.com
dig example.com
ping example.com
traceroute example.com
ss -tan
-
curl -vreveals useful connection, TLS, and HTTP details. -
dighelps inspect DNS records and TTLs. -
pingtests ICMP reachability, not HTTP availability. -
tracerouteattempts to reveal the path through network hops. -
ssshows socket information and connection states.
Not every network responds to these diagnostic tools, so a failed ping or missing traceroute hop doesn't necessarily mean a service is down.
The goal is to connect what the tools show with what's happening underneath the request.
The mental model
Application
↓
HTTP
↓
TLS
↓
TCP / QUIC
↓
IP
↓
Network
↓
Remote server
Each layer has its own responsibilities, failure modes, and performance characteristics.
A network request isn't a single operation. It's a chain of operations across multiple layers, often involving more than one machine.
And that leads to the next question.
When the request reaches the backend and the application asks a database for some data, how does the database actually find it? Why are some queries fast while others are slow?
That's where Part 4 — Databases + Storage begins.
Top comments (0)