2026年11月12日
2026年11月12日
Nginx tcp_nopush vs tcp_nodelay: What They Do and How to Set Them
This article is a localized edition of the Japanese original. Read the Japanese original
The short answer
| Directive | Default | What it does | Recommendation |
|---|---|---|---|
tcp_nopush |
off |
When sending with sendfile, uses TCP_CORK on Linux (TCP_NOPUSH on FreeBSD) to send only full packets |
on, together with sendfile on |
tcp_nodelay |
on |
Uses TCP_NODELAY to send even small data without waiting |
Keep the default on |
Both can be set in http, server and location (official Nginx documentation, ngx_http_core_module). For a typical website, these three lines in the http block are all you need.
http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
}
Background: when TCP sends data
Nagle’s algorithm and TCP_NODELAY
TCP has a mechanism that holds back small pieces of data and sends them in batches (Nagle's algorithm). It keeps the link from filling up with tiny packets, but combined with delayed ACKs on the other side it can hold up short responses.
TCP_NODELAY is the socket option that turns Nagle's algorithm off. Nginx's tcp_nodelay defaults to on, and according to the official documentation it is enabled when a connection moves into the keep-alive state. It is also enabled on SSL connections, for unbuffered proxying and for WebSocket proxying.
TCP_CORK and tcp_nopush
TCP_CORK (Linux) does the opposite: it "corks" the socket, and while it is set, partial packets are held instead of sent. With tcp_nopush on, Nginx uses this option when sending with sendfile, and according to the official documentation this lets it:
- send the response header and the beginning of the file in one packet
- send the file in full packets
Because a small header-only packet no longer goes out first, fewer packets are sent.
When tcp_nopush helps and when it does not
tcp_nopush takes effect only when sendfile is used (official documentation). sendfile defaults to off, so writing tcp_nopush on without sendfile on does nothing.
sendfile() sends a file on disk straight to the socket inside the kernel, so it is used only when Nginx serves a file as is.
| Response type | sendfile | tcp_nopush |
|---|---|---|
| Static files over HTTP (images, CSS, JS) | Used | Takes effect |
| Static files over HTTPS | Usually not used (Nginx encrypts with OpenSSL before sending) | Usually no effect |
| Responses from PHP-FPM (FastCGI) or a proxied upstream | Not used | No effect |
Over HTTPS, sendfile can be used only in setups that combine OpenSSL 3.0 with kernel TLS (kTLS) (the Nginx changelog lists "support for SSL_sendfile() when using OpenSSL 3.0"). kTLS is not enabled by default, so on most HTTPS sites tcp_nopush has little effect.
For WordPress, the pages PHP generates come from PHP-FPM and are not affected; only images in wp-content/uploads and theme CSS/JS served directly by Nginx are. Enabling it does no harm, but do not expect a visible speed-up.
Why turning both on is not a contradiction
tcp_nopush ("batch it up") and tcp_nodelay ("send now") look like opposites, but Nginx uses them at different times.
tcp_nopush: used while a file is being sent withsendfiletcp_nodelay: used when the connection moves into the keep-alive state (after the response is sent, while waiting for the next request), among other cases
While the file is being sent, packets are kept full to reduce their number, and the small last part of the response goes out without waiting. That is why both are commonly set to on.
Setting tcp_nodelay off can hold up small responses on keep-alive connections, so leave it at the default on unless you have a specific reason.
Configuration steps
1. Check the current settings
The default nginx.conf differs by distributor. In the official Nginx Docker image (stable as of October 2026), for example, sendfile on; is active and #tcp_nopush on; is commented out. Check the full configuration that is actually loaded.
sudo nginx -T 2>/dev/null | grep -nE 'sendfile|tcp_nopush|tcp_nodelay'
2. Add the settings
Open /etc/nginx/nginx.conf. Edit the http block in this file. If a directive is already there, change its value instead of adding it again (the same directive twice in one block makes nginx -t fail with an error such as "sendfile" directive is duplicate).
http {
sendfile on;
tcp_nopush on;
tcp_nodelay on;
# ... existing settings ...
}
To apply it only where you serve video or other large files, you can put it in a location.
location /video/ {
sendfile on;
tcp_nopush on;
}
3. Check the syntax and apply
There is no need to stop Nginx. Check the syntax, and if it passes, reload the configuration.
sudo nginx -t
sudo systemctl reload nginx
If nginx -t does not print syntax is ok and test is successful, do not reload; fix the line it reports.
4. Verify after applying
# Values in effect
sudo nginx -T 2>/dev/null | grep -nE 'sendfile|tcp_nopush|tcp_nodelay'
# Static files are served normally
curl -sI https://example.com/wp-includes/js/jquery/jquery.min.js | head -n 1
Caveats
- Shared folders and network file systems: on virtual machine shared folders and similar setups,
sendfileis known to serve stale content. If file changes do not show up in a development environment, setsendfile off;there only (tcp_nopushthen stops working too). - Measuring the effect: the impact on speed depends on the network and file sizes. Compare the same requests before and after the change and decide based on the numbers.
- Interaction with
directio: withdirectio,sendfileis not used for the requests it applies to (official documentation).
Summary
tcp_nopushonly works withsendfile; it sends the header together with the start of the file, and the file in full packets. Default:off.tcp_nodelayturns off Nagle's algorithm. Default:on; used on keep-alive and SSL connections.- For most sites,
sendfile on; tcp_nopush on; tcp_nodelay on;is fine. - HTTPS (without kTLS) and PHP responses do not use
sendfile, sotcp_nopushhas limited effect. - After a change, apply it with
nginx -tandsystemctl reload nginx, and confirm the values withnginx -T.
For configuring sendfile itself, see Enabling sendfile and tcp_nopush in Nginx; for an overview of nginx.conf, see Basic nginx.conf settings.
Questions about WordPress? The publisher of this site is based in Japan and replies in Japanese. Contact (Japanese)