When would you choose UDP over TCP, given that TCP is reliable and UDP is not?
TCP guarantees an ordered byte stream and pays for it with head-of-line blocking and retransmissions that arrive too late to be useful. UDP is right when a late packet is worthless, when you need multicast, or when you intend to build your own reliability with different trade-offs.
What the interviewer is scoring
- Whether the candidate can name a case where retransmission actively harms the application
- That head-of-line blocking is explained as an ordering consequence rather than a bandwidth one
- Does the candidate know what UDP still provides rather than treating it as raw IP
- Whether they recognise that choosing UDP means reimplementing whichever guarantees they need
- That congestion control is identified as a responsibility, not just a TCP feature to escape
Answer
What each protocol actually promises
TCP gives you a connection-oriented, reliable, ordered byte stream with flow control and congestion control. Every one of those words is a promise the kernel keeps for you: bytes arrive, they arrive once, they arrive in the order sent, and the sender slows down when the network or the receiver is struggling. Note that it is a stream and not a sequence of messages — TCP will happily coalesce two writes into one segment or split one write across two, which is why every protocol built on it needs its own framing.
UDP gives you connectionless datagrams with a checksum. Message boundaries are preserved, which is a genuine feature and the thing people forget it offers. Nothing else is promised: a datagram may be lost, duplicated, or delivered out of order, and there is no feedback to the sender about any of it.
The framing difference matters more than it sounds. With UDP, one sendto becomes one recvfrom of exactly that size. With TCP you must delimit messages yourself, and getting that wrong is one of the most common sources of protocol bugs.
Reliability that arrives too late is not reliability
The case for UDP that candidates most often miss is not about overhead. It is that TCP's guarantees can be actively counterproductive.
Consider a voice call. A packet of audio is lost. TCP will detect the gap, retransmit, and deliver that audio correctly — perhaps 150 milliseconds later, by which time the moment it belonged to has passed. Worse, because TCP guarantees order, every packet that arrived after the lost one is held in the kernel's receive buffer and withheld from your application until the gap is filled. One lost packet stalls the stream.
That is head-of-line blocking, and it is a consequence of the ordering guarantee rather than of bandwidth or of retransmission cost. For a voice call the correct behaviour is the opposite of what TCP does: discard the lost packet, conceal the gap, and keep playing. A 20-millisecond dropout is nearly imperceptible; a 150-millisecond stall is not.
The general form: when data has an expiry, reliability that outlives the expiry is worse than loss, because it consumes the delivery slot of data that is still current. Live video, game state, sensor readings, and market data all have this shape. A position update from 200 milliseconds ago is not useful, and there is already a newer one behind it.
The other reasons to reach for UDP
Multicast and broadcast are simply not available over TCP, which is point-to-point by definition. If one sender must reach many receivers with the network doing the fan-out, UDP is the only option at the transport layer.
Request-response smaller than a connection. A DNS query and its answer fit in one datagram each. Establishing a TCP connection costs a round trip before any data moves, plus connection state on both ends. For a single small exchange that overhead can exceed the payload, which is why DNS defaults to UDP and falls back to TCP when a response is too large or when the exchange needs a reliable stream.
You want different trade-offs than TCP offers. This is what QUIC does. It runs over UDP and is entirely reliable, but because it implements reliability itself it can carry multiple independent streams and let a loss in one stream block only that stream, rather than everything behind it. It also folds the transport and cryptographic handshakes together, so a connection establishes in one round trip instead of the two or three that TCP plus TLS requires. Choosing UDP was not a decision to be unreliable; it was a decision to escape TCP's fixed choices while keeping the parts worth keeping.
What you take on when you choose it
Every guarantee you need and UDP does not provide, you now implement. Sequence numbers if you need ordering. Acknowledgements and retransmission if you need reliability. Some form of framing beyond one message per datagram if your messages can exceed the path MTU, since IP fragmentation is best avoided.
The obligation people neglect is congestion control. TCP backs off when the network signals distress; UDP has no such mechanism, so an application that keeps sending into a congested path will make things worse for everyone including itself. Writing a naive UDP flood and observing that it is faster than TCP under contention is measuring your willingness to be antisocial, not the protocol.
That is the honest framing of the choice. UDP is not the lightweight option. It is the option that hands you the mechanism so you can choose the policy, and if you find yourself reimplementing acknowledgements, ordering and backoff, you have rebuilt TCP with fewer decades of production hardening behind it. Reach for an existing protocol over UDP before writing your own.
Choose UDP when late data is worthless, when you need one-to-many, or when you genuinely need different guarantees. Choosing it to avoid overhead usually means paying that overhead again, worse, in your own code.
Likely follow-ups
- QUIC runs over UDP and is reliable. What did that let it change?
- You are sending 200-byte telemetry every second from 50,000 devices. Which do you pick and why?
- What does UDP do about congestion, and why should you care about being a good citizen?
- Why is DNS traditionally UDP, and when does it fall back to TCP?
Related questions
- Your application cannot reach a service that should be up. Walk me through diagnosing it from the shell.mediumAlso on networking and tcp6 min
- If you were writing a small value type in Python, which dunder methods would you implement, what would you let a dataclass generate, and how does super() decide what to call?mediumAlso on protocols4 min
- Walk me through everything that happens when you type a URL into the browser and press enter.mediumAlso on tcp6 min
- A dashboard has been showing the same temperature for two days and nobody noticed. Walk the path and tell me what would have caught it.hardSame kind of round: concept6 min
- Everyone in the business calls it the fax queue, and nothing has been faxed since 2014. Do you keep that name in the code?mediumSame kind of round: concept4 min
- How do you split a story that is too big to fit in a Sprint?mediumSame kind of round: concept3 min
- The business insists on a requirement that nobody can test — "the system must be intuitive". What do you write instead?mediumSame kind of round: concept4 min
- How does your order placement change on a venue that allocates pro rata within a price level instead of first in, first out?hardSame kind of round: concept6 min