System Design

Why is the first request always slower? The TCP handshake costs a full RTT

TL;DR

Before the first byte of data can be sent, client and server must complete the TCP handshake, costing one full round trip (RTT). Follow-up requests reuse the open connection (keep-alive), so they’re exactly one RTT faster.

Timeline with an 80ms RTT

TimeEvent
0 → 40msClient sends SYN to the server.
40 → 80msServer replies SYN-ACK (ack = SYN’s seq + 1).
80msClient sends ACK together with GET / — only now does the first data byte leave.
160msThe first response arrives back at the client.
+80msA second request (GET /app.js) reuses the connection: just 1 RTT.

How to put it to work

  • Reuse connections: Enable keep-alive and connection pooling (HTTP clients, DB drivers) to avoid repeated handshakes.
  • Frontend: Use <link rel="preconnect"> for critical origins (fonts, API, CDN) to start the handshake early.
  • Infrastructure: HTTP/2 multiplexes many requests over one connection; HTTP/3 (QUIC) combines transport and TLS handshakes to cut round trips. Moving servers closer to users (CDN/edge) shortens the RTT itself.
  • When measuring: Separate connection time from server processing time so you don’t blame the backend unfairly.