- Nagle's algorithm reduces tinygrams by limiting them to a small segment without ACK per connection, improving efficiency on slow networks but adding latency.
- Its interaction with delayed ACKs can introduce pauses of up to 500 ms in write-write-read patterns and request-response protocols.
- TCP_NODELAY and TCP_QUICKACK allow you to disable Nagle and/or Delayed ACK to prioritize latency in interactive applications and modern distributed systems.
- The decision to use Nagle or not should be based on the actual traffic pattern: massive throughput versus critical one-way latency.
When working with networks, sockets, or simply struggling with TCP application latency, it's only a matter of time before you encounter the infamous Nagle's algorithm (Nagle's AlgorithmIt is one of those mechanisms in the TCP/IP stack that we almost never configure manually at the beginning, but it can make the difference between a smooth app and one that runs "stuttering" with mysterious delays of hundreds of milliseconds.
In this article we will calmly break down what Nagle's algorithm is, what problem it aimed to solve in the 80s, and how it combines (sometimes fatally) with the delayed ACK mechanism. when is it appropriate to turn it off We'll cover TCP_NODELAY and the options available in major operating systems for tuning its behavior. Everything is explained simply.
What is Nagle's algorithm and what problem does it try to solve?
Nagle's algorithm arose from a very specific need: avoid the avalanche of tiny packets (tinygrams) that saturated slow networks in the early days of TCP. Think of interactive terminal applications, where each keystroke sent a single byte: for each character, 1 usable byte traveled plus 20 bytes of TCP header and 20 of IP header. That is, 41 bytes in total, of which only 1 was actually data: an overhead of 4000%, an absolute absurdity if repeated thousands of times.
John Nagle proposed a “simple and elegant” solution: as long as there is data sent without acknowledgment (without ACK) In a TCP connection, the sender must restrain itself and not keep sending small new segments. This way, instead of firing off tiny packets one after another, the system waits for ACKs to arrive or for more data to accumulate, so that larger, more efficient segments can be formed.
In simple terms, the idea is that a TCP connection can only have one small unconfirmed segment in flight. The remaining small fragments generated by the application remain in the socket buffer until the pending small segment receives its acknowledgment, at which point the system packages the accumulated data into a larger segment and sends it all at once.
This logic makes the algorithm somewhat self-adaptive: the slower the network or the greater the latency, the longer it takes for ACKs to return and the more the data is grouped within each segment. On high-latency, relatively limited-bandwidth WAN links, this was pure gold for improving performance. overall traffic efficiency.

Formal definition and internal functioning
The original specification of Nagle's algorithm, contained in RFC 896 on congestion control in IP/TCP networks, summarizes its behavior as follows: it should inhibit the sending of new TCP segments When data arrives from the application, it checks if there is previously transmitted data that has not yet been recognized. Based on this definition, many implementations express it in pseudocode.
In practical terms, the logic for each TCP connection can be formulated as follows: if new data arrives and the shipping window If the amount of unacknowledged data allowed is greater than or equal to the MSS, and there are at least MSS bytes in the buffer, a full-size MSS segment is sent immediately. If this condition is not met, but there is still unacknowledged data "in the pipeline," this new data is queued and a wait is made for an ACK. When there is no unacknowledged data, any new data received from the application is sent immediately.
Ultimately, what matters is the relationship between the MSS (Maximum Segment Size)The window size and the volume of data that the application gradually outputs are key factors. If the application's flow is very granular (many small writes), Nagle acts as a "funnel" and groups the data; if it's more voluminous, the impact is diluted and the algorithm is less intrusive.
Some more modern descriptions add minor nuances, such as triggering the send also when the accumulated data reaches half the window size or exceeds the MSS, but the core of the mechanism remains the same: do not send the next small segment until the previous one is confirmed.
Delayed ACKs: delayed acknowledgments to reduce overhead
In parallel with Nagle, and around the same time, another optimization was introduced in TCP that is just as famous today: the Delayed ACKThe idea was very reasonable for the networks of that time: if you have just received a segment and are about to send data back, why not wait a little while and use that outgoing packet to "piggyback" the ACK in the same header?
This mechanism is based on a timer: upon receiving data, the receiver stores the ACK and waits a short interval (typically between 200 and 500 ms) to see if it appears during that time outbound traffic to which the acknowledgment can be added. If nothing arrives, when the timer expires, the ACK is sent separately.
The result is a reduction in the total number of ACKs circulating on the network, which saves TCP/IP headers and decreases the load on routers and endpoints. In many cases, especially with interactive protocols that use character echo (such as certain Telnet configurations), the receiver can group several ACKs into a single ACK without affecting perceived latency.
However, this technique has a downside: that deliberate delay of up to half a second It can be lethal for certain time-sensitive applications. And when combined with Nagle's algorithm, the unwanted effects skyrocket, generating crashes and periodic pauses that are very difficult to diagnose at first glance.
The explosive combination: Nagle + Delayed ACK
Nagle's major practical problem doesn't arise on its own, but rather when it's combined with the delayed ACKsBoth functionalities were designed independently in the early 80s, and according to Nagle himself, the combination “is terrible.” There is no explicit coordination between them, so they can fall into a kind of mutual wait loop.
Imagine an application that performs two consecutive writes over a TCP connection and then a read, waiting for the data generated by the second write. With Nagle enabled, after the first small segment, the TCP stack won't send the second small packet until it receives an ACK for the first. But if the receiver uses Delayed ACK, that acknowledgment won't be sent immediately; instead, it will wait until it can be attached to a response packet or until the 200-500 ms timer elapses.
The result is an artificial bottleneck: the sender does not send the second segment because it is waiting for the ACK of the first, and the receiver does not send the ACK because it is waiting for more traffic. They both get stuck until the delayed ACK timer expires, introducing an extra latency of up to 500 ms in each such sequence.
This pattern is especially harmful in protocols of non-pipelinized request-response, such as HTTP over persistent connections when requests or responses are split into multiple segments and the last packet is partial. With the original algorithm, if a write generated 2n segments where the first 2nThe first segment was full-size, and the last was small; TCP held the small segment while waiting for an ACK. If the receiver also delayed the ACKs, the small segment would fall behind by up to half a second.

When does it make sense to disable Nagle: TCP_NODELAY
Modern TCP stacks often expose a socket option to explicitly disable Nagle: the well-known TCP_NODELAY optionIt has been available since 4.2BSD (1983) and has been inherited by many descendants, including most Unix systems, macOS, and Windows. In AIX and Windows, for example, Nagle is enabled by default and can be disabled per socket using this flag.
Disabling the algorithm makes perfect sense when the absolute priority is the unidirectional latency Low bandwidth and small but very frequent data volume per message. In the context of gamingTypical examples include real-time multiplayer video games, remote desktops where every mouse movement must be noticed instantly, or interactive tools that send keystrokes one by one, such as telnet or rsh.
In these environments, the delay of hundreds of milliseconds that the Nagle + Delayed ACK combination can introduce is unacceptable: the user clearly perceives that the interface is not responding in time. Therefore, many low-latency applications enable TCP_NODELAY on all their connections, sacrificing some header efficiency in exchange for a much faster interaction.
It is also common for frameworks and libraries for "chatty" protocols, such as certain SSL/TLS tunnels, Citrix-type solutions, or systems that perform many short control exchanges, to opt for disable Nagle by defaultbecause in practice it costs them more in latency than they save on headends.
However, for massive traffic such as HTTP, SOAP, XMLRPC downloads or large file transfers, where throughput is dominant and the cost of each header is insignificant compared to the volume of data, keeping Nagle active is usually not problematic and, in many cases, there is no noticeable difference when turning it off.
Does Nagle still make sense in modern systems?
If we look at current networks, with data centers where a round trip (RTT) is measured in hundreds of microseconds or a few milliseconds between nearby regions, Nagle's original justification loses its force. Blocking the transmission of a segment until the next ACK no longer involves seconds of waiting, but it can be an unnecessary obstacle when every microsecond counts.
Furthermore, nowadays it's rare for serious applications to send raw 1-byte packets. Most distributed systems, databases, and backend services construct larger messages, use TLS (which adds its own overhead), and serialize data with JSON, Protobuf, and derivatives. The underlying problem with tinygrams has been "leveled up" and is largely managed from the... application layer, which usually groups the information logically before dumping it into the socket.
That's why many engineers designing low-latency services in modern data centers start with a very pragmatic rule: for their internal control traffic, the safe option is to always enable TCP_NODELAY, and any throughput problems will be dealt with in another way. In other words, it's better to risk using a few extra headers than to introduce multi-RTT blocking at critical points in the business logic.
This does not mean that Nagle has ceased to be useful, especially in contexts of narrow or very noisy links (for example, SLIP, certain mobile or satellite links) where each package is expensive. But it does reinforce the idea that its use should be conscious: in many current enterprise deployments, the default setting of having it enabled is not the best fit for the applications running on top of it.
An additional argument is that Nagle's own recommendation for avoiding pathological behavior is that applications should not follow the write-write-read pattern, but rather write-read-write-read or write-write-write, grouping operations and emptying the buffer only when absolutely necessary. This reinforces that the responsibility of not "spilling" bytes to the socket Ideally, it should fall on the user code.
Disable Delayed ACK: TCP_QUICKACK and other mechanisms
Another way to circumvent the problems of the Nagle + Delayed ACK combination is to address the other side: instead of disabling Nagle, disable or soften the behavior of delayed ACKs. Here, the situation is more complex, because the interfaces vary considerably between operating systems.
In Linux there is the flag TCP_QUICKACK Since kernel 2.4.4 (2001), this allows the stack to be asked to recognize incoming segments more quickly. Similar or related mechanisms also exist in Windows, such as the operation SIO_TCP_SET_ACK_FREQUENCY, and logging parameters such as TcpAckFrequency which, if set to 1, force the immediate sending of ACKs.
In FreeBSD, the default behavior of deferred ACKs is controlled by the sysctl parameter net.inet.tcp.delayed_ackwhich can be adjusted to make acknowledgments more aggressive or relaxed as needed. However, in Linux there is no such simple global equivalent switch: delayed ACK handling is more deeply embedded in TCP's internal logic.
Although these options exist, many distributed systems developers use them cautiously. On the one hand, They are not portable Cross-platform compatibility complicates writing maintainable generic code; furthermore, its semantics are sometimes unintuitive and dependent on the kernel version. Moreover, even with fast ACKs, the kernel may still temporarily hold onto data that the application would prefer to send immediately, so the root cause of the problem is not eliminated.
For all these reasons, in many cases the preferred tactic is more direct: if the priority is that each call to write() really means "send this now", the tendency is to activate TCP_NODELAY and accept the small cost in headers, instead of trying to tame the behavior of Delayed ACK with system-specific flags.
How to decide whether to enable or disable TCP_NODELAY
The big practical question is: when is it advisable to have Nagle enabled, and when is it better to disable it with TCP_NODELAY? There's no universal rule, but there are some fairly solid guidelines based on the type of traffic and observed behavior.
If your service primarily handles bulky transfers For non-interactive tasks (file downloads, large HTTP responses, well-buffered streaming streams), the priority is usually throughput and overall efficiency. In these cases, leaving Nagle enabled is reasonable and rarely introduces noticeable latency issues.
Conversely, if you're dealing with highly interactive applications that send many small messages—online games, remote desktops, Citrix, certain SSL tunnels, or protocols that require numerous short handshakes—Nagle tends to be a hindrance. Enabling TCP_NODELAY usually results in clear gains in responsiveness for the user.
A more analytical way to look at it is to instrument the network and observe statistics such as the number of tinygrams (packets with very small payloads) and the amount of delays attributable to Nagle. In-depth traffic analysis tools can help you see what percentage of your packets are tiny and how much time they spend "stuck" due to these mechanisms.
If, after observing for a while, you see many tinygrams but few delays due to Nagle, it might be a good idea to keep it active because it's helping to reduce them. Conversely, if you see many tinygrams and a high percentage of delays due to the algorithm, it's a clear sign that your traffic pattern isn't taking advantage of Nagle, and disabling it could be beneficial.
As with almost everything in performance, the final decision usually requires several iterations: tweaking options, measuring, waiting, reviewing metrics, and, based on the results, adjusting again. And all of this with the understanding that the mix of applications on a network changes over time, so what works today may not be ideal in a few months.
Alternatives and solutions when TCP doesn't fit
In some extreme scenarios, even disabling Nagle and adjusting Delayed ACK isn't enough to achieve the desired latency. If your application is constantly sending tiny frames and any additional delay is unacceptable, TCP might not be the best transport for you.
In these cases, many developers opt for connectionless protocols such as UDPIn this environment, there is no congestion control or delivery guarantees, but there is minimal latency and a complete absence of mechanisms like Nagle or delayed ACKs. However, everything that TCP does for you—retransmissions, ordering, loss control, etc.—must be implemented at the application layer.
Another alternative is to redesign the application protocol itself to avoid problematic write-write-read patterns and reduce the minimum number of swaps required to complete each logical operation. Sometimes, a simple change in how messages are grouped can circumvent the worst effects of Nagle without altering socket options.
In large corporate environments, they also use adjustments to load balancers and proxiesThis allows you to dynamically enable or disable TCP_NODELAY based on the type of traffic detected, or selectively reduce Delayed ACK timers. This approach enables adapting behavior to highly heterogeneous traffic mixes without requiring modifications to all end applications.
In any case, before spending money on more hardware or new links, it's usually very worthwhile to check if your TCP parameters (Nagle, Delayed ACK, window size, buffers, etc.) are truly aligned with your network's actual usage patterns. It's not uncommon for well-executed adjustments at these layers to achieve significant improvements without changing a single cable.
Given all of the above, a thorough understanding of how Nagle's algorithm works and how it interacts (or works well) with Delayed ACK, TCP_NODELAY, and TCP_QUICKACK is almost mandatory if you are concerned about latency and performance in your TCP applications: ultimately, deciding whether to prioritize efficiency or immediacy in each case is what makes the difference between a network that "runs on its own" and one that always seems to be running with the handbrake on.
Index
- 1 What is Nagle's algorithm and what problem does it try to solve?
- 2 Formal definition and internal functioning
- 3 Delayed ACKs: delayed acknowledgments to reduce overhead
- 4 The explosive combination: Nagle + Delayed ACK
- 5 When does it make sense to disable Nagle: TCP_NODELAY
- 6 Does Nagle still make sense in modern systems?
- 7 Disable Delayed ACK: TCP_QUICKACK and other mechanisms
- 8 How to decide whether to enable or disable TCP_NODELAY
- 9 Alternatives and solutions when TCP doesn't fit
Editor specialized in technology and internet issues with more than ten years of experience in different digital media. I have worked as an editor and content creator for e-commerce, communication, online marketing and advertising companies. I have also written on economics, finance and other sectors websites. My work is also my passion. Now, through my articles in Tecnobits, I try to explore all the news and new opportunities that the world of technology offers us every day to improve our lives.