Skip to the content
Software Made Clear Diagrams that show the mechanism About

TCP vs UDP

Know when a dropped packet breaks your feature and when it costs nothing, so you stop reaching for TCP by reflex and paying for a round trip you never needed.

5 min read Updated September 23, 2026 Last verified August 19, 2026
ANSWER

Use TCP when a missing byte breaks the meaning, and UDP when a late byte is worse than a lost one. TCP guarantees order and delivery by waiting and re-sending; UDP guarantees neither and is finished the moment it hands the packet over.

IN PLAIN TERMS

Think of TCP as a signed-for parcel: the courier waits for a signature, comes back if nobody answers, and the parcels arrive in the order you sent them. UDP is a postcard dropped in a box — cheap, immediate, and nobody tells you if it never arrives.

A few kilobytes should not feel slow, and yet it does. The usual reason is not bandwidth and not the server — it is the handshakes and acknowledgements you are paying for and may not need. Both questions come down to the same fact — TCP buys you order and delivery, and the price it pays is waiting.

CLIENTCLIENTSERVERSERVERTCP — waits for the handshake before sendingUDP — sends immediately, no handshakeSYNSYN-ACKACK + DATADATAno ACK arrivesRESENDDATAlost — no retrytime →TCP — waits for the handshake beforesendingSYNSYN-ACKACK + DATADATAno ACK arrivesRESENDCLIENTSERVERUDP — sends immediately, no handshakeDATAlost — no retryCLIENTSERVER
TCP will not send your data until the other end has agreed to receive it; UDP never asks.

What the handshake buys you#

A normal TCP connection begins with SYN, SYN-ACK, and a final ACK. After receiving the SYN-ACK, the initiator may put application data in that third, ACK-bearing segment; an empty ACK followed by a separate data segment is only one valid sequence. The exchange establishes starting sequence numbers so subsequent bytes can be placed and acknowledged. TCP Fast Open can even carry data in a SYN, but that is an optional extension, not baseline handshake behaviour.

An ACK after that point is a narrower promise than it sounds. It means the segment reached the kernel’s receive buffer on the other machine — not that your application has read it, and not that it processed it without error. TCP’s contract ends at the socket. Whether the byte actually did anything useful is a question TCP was never asked and cannot answer.

UDP skips that setup. There is no handshake or agreed sequence in UDP itself. A UDP sender can send its first datagram immediately; a TCP initiator normally waits for the SYN-ACK before sending its first application bytes, which can accompany the final ACK as the diagram shows.

What re-sending costs when you did not need it#

“Reliable” is usually read as a pure upside, and the cost it hides is head-of-line blocking. TCP must deliver bytes to your application in the order they were sent, so when one segment is lost, every segment that arrived after it — correctly, already sitting in the receive buffer — is held back too. Nothing downstream of the gap moves until the missing piece is resent and arrives. One lost packet stalls the whole stream, not just the byte that went missing.

That resend is automatic and invisible to your code, which is different from a retry your own application decides to issue at the request level. When the network loses a request instead of a packet, the retry is the client’s only option — this article covers what the server owes a request it is seeing for the second time.

UDP has none of this bookkeeping to fall back on. A lost UDP packet is simply gone; nothing behind it waits, and nothing resends it unless your application decides to. That absence is a cost when you needed the data — and free when you did not.

Picking one on purpose#

The trade sits in one place: TCP pays with a handshake up front and a stall whenever a segment is lost, in exchange for never handing your application a gap or an out-of-order byte. UDP pays nothing up front and stalls for nothing, in exchange for making loss and ordering entirely your problem. Neither is the safe default — each is the wrong guarantee to buy for the other one’s workload.

The case that shows it clearest is a live video or game feed carried over TCP. One dropped packet stalls the stream while TCP waits for the resend, so the viewer sees a freeze — and then, when the resend finally lands, a burst of frames arrive all at once, each one older than the moment the viewer is now watching. The resend did its job and delivered the missing data intact. By the time it arrived, that data was worthless: the game had moved on, the video had a newer frame ready, and nobody downstream wanted the stale one anymore. Reliability was the wrong guarantee to buy — the feed needed the freshest packet, not every packet.

This one choice is a small piece of a larger subject: the distributed-systems path is aimed at what the network does to the assumptions you bring to it.

Situation Take Because
A missing byte changes the meaning TCP Order and delivery are the whole point.
A late frame is worse than a lost one UDP Re-sending delivers something already stale.
Many small messages, loss tolerable UDP No handshake, no per-connection state.
You would rebuild acknowledgements yourself TCP You are re-implementing it, worse.
Situation
A missing byte changes the meaning
Take
TCP
Because
Order and delivery are the whole point.
Situation
A late frame is worse than a lost one
Take
UDP
Because
Re-sending delivers something already stale.
Situation
Many small messages, loss tolerable
Take
UDP
Because
No handshake, no per-connection state.
Situation
You would rebuild acknowledgements yourself
Take
TCP
Because
You are re-implementing it, worse.

IF YOU REMEMBER ONE THING

TCP and UDP are not a strong choice and a weak one. They are two different answers to “what should happen to a byte that goes missing” — and only your feature knows which answer it needs.

Questions people also ask

5 QUESTIONS
Does TCP guarantee my application received the data?

No. An ACK only confirms the segment reached the receiving kernel's buffer — it says nothing about whether your application has read it yet, let alone processed it correctly. The guarantee stops at the socket, not at your code.

Why is UDP called unreliable if it usually works?

"Unreliable" describes the promise, not the typical outcome. On a healthy path almost every packet arrives; the word just means UDP itself does nothing to notice or fix the rare one that does not, so if that matters to you, you have to build it.

What is head-of-line blocking?

One lost segment forces TCP to hold every segment that arrived after it, even the ones already sitting correctly in the receive buffer, because data has to reach your application in order. The whole stream waits on the one piece that has to be resent.

Does HTTP/3 use TCP or UDP, and why?

QUIC runs over UDP and supplies ordered byte streams. A QUIC packet can carry frames from more than one stream; losing it can delay each affected stream while the missing data is recovered. Other streams can continue, avoiding the connection-wide TCP head-of-line stall that affects HTTP/2. Packet loss detection and recovery operate at the connection level, while delivery order is tracked per stream.

Can I get ordering without TCP?

Yes — put a sequence number in each UDP packet and reorder them yourself on arrival, which is what real-time protocols like RTP do. You get ordering without paying for retransmission, because you decide what a late arrival means for your data instead of the transport deciding for you.

The library Browse all articles