Menu

Guidefor server owners4 min read

Network flush consolidation: the lag bottleneck TPS doesn't show

A healthy TPS doesn't mean a healthy network layer. How per-packet flushing turns into a syscall storm, and how batching those flushes fixes it.

A bottleneck that never shows up in /tps

Every guide to server lag starts with TPS and MSPT, because the tick loop is where most lag comes from. But a server can hold a perfect 20 TPS, an MSPT nowhere near the 50 ms budget, and still feel laggy to players. Movement stutters, block placements arrive late, chunks pop in behind the player instead of ahead of them.

When that happens, the tick loop isn't the problem. The network layer is, and it's a separate bottleneck with a separate fix.

What a flush actually costs

Sending data over a socket is normally two steps: write, which queues bytes in a buffer, and flush, which tells the operating system to actually push those bytes out. The flush is a syscall, a call out of your program and into the kernel. Syscalls are not free. Each one is a context switch, and context switches cost real CPU time regardless of how much data they move.

A Minecraft server writes a large number of small packets per player per tick: entity movement, chunk data, block updates, and more. The naive way to send them is to flush after every single write. That's correct, easy to reason about, and it works. It just doesn't scale, because now every few bytes of payload pays the full fixed cost of a syscall.

A widely read community writeup of a Paper-fork rewrite of Minecraft's network flushing measured this directly: batching the flushes brought one server's packets-per-second at the OS level down from roughly 16,000 to 170, about a 97% reduction, with no change to what data was actually sent to players. Same packets, same game state, a fraction of the syscalls required to deliver them.

Flush consolidation: the fix

Flush consolidation means queueing every packet that needs to go out during a tick, or a shorter window, and flushing once at the end instead of after each write. The data sent is identical. What changes is how many times the server asks the kernel to move it, which is where the cost was hiding.

This isn't a Minecraft-specific idea. Netty, the network library Minecraft's server and most Java game servers run on, has carried a smart auto-flush mechanism for writeAndFlush since Netty issue #1759, precisely to reduce the syscall count generated by naive per-message flushing. Minecraft server software builds on top of that: BungeeCord pull request #3393, contributed by Janmm14 and titled "Consolidate flushes, leading to reduced syscalls," did the same consolidation at the proxy layer and was measured at roughly 30 to 50% lower CPU use. PaperMC/Paper issue #674 documents the failure mode from the other direction: chunk sending flooding the netty queue and delaying other packets, a real, reported cause of join lag in production.

Three independent reports, same underlying mechanism: uncombined flushing multiplies syscall overhead, and batching it removes the multiplication without touching game logic.

Why this scales with player count, not tick complexity

A single player generates a modest packet stream and a per-packet flush habit barely registers. The cost is multiplicative: more players means more packets per tick, and a naive flush-per-packet implementation means the syscall count grows in lockstep with the packet count. A hundred players each sending movement and chunk updates every tick is exactly the load where an uncombined flush pattern turns into the kind of syscall storm the 16,000-packets-per-second figure describes.

This is also why it can hide from TPS entirely. TPS and MSPT measure the main thread doing world simulation. Network I/O for a Paper-based server largely happens off that thread. A server can be perfectly fast at simulating the world and still spend enormous CPU time on syscalls moving that world's packets out the door, and none of it will show up in /tps.

Where this is different from the lag causes you already know

Not TPS or tick lag. Fixing Minecraft server lag covers the main thread: entities, view distance, redstone, world generation, all things that eat the 50 ms tick budget. Flush consolidation lives in the network layer, which is a different subsystem with a different failure mode. A server can have this problem with a perfect MSPT, and fixing MSPT issues will not touch it.

Not JVM or garbage collection tuning. The startup flags reference covers heap sizing and garbage collector choice, tuning how the JVM manages memory. Flush consolidation is about how many times the server calls into the kernel to push bytes over a socket. Neither fix substitutes for the other, and a server can need one, both, or neither.

What you can actually do about it

This is the honest part: there is no server.properties value or startup flag called flush-consolidation to switch on. It isn't a tunable, it's a rewrite of how the network code batches its writes, and that rewrite has to happen inside the server software itself.

That makes the practical guidance narrower than most fixes on this site. The action available to a server owner is staying on a current Paper or Purpur build. Netty-layer improvements like this land in the underlying software as the projects ship them, not in your config, and running an old build means missing fixes you have no way to apply yourself. If you're troubleshooting stutter that doesn't match your TPS and MSPT numbers, confirming you're on a recent build is the first thing to check, well before touching config.

If your platform doesn't ship a fix like this, there's nothing to configure around it. That is a real limitation of running behind on updates, not a settings problem you overlooked.

Frequently asked

If TPS and MSPT both look fine, can the server still be laggy?

Yes. TPS and MSPT measure the tick loop, the thread that runs the game world. Sending packets to players is a separate cost on top of that. A server can finish every tick in 10 ms and still stutter for players if the network layer is doing tens of thousands of syscalls a second to push those ticks' packets out.

What exactly is a flush, in networking terms?

Writing to a socket usually queues bytes in a buffer rather than sending them immediately. A flush is the call that tells the operating system to actually push the queued bytes out. Each flush is a syscall, a context switch out of your program and into the kernel, which costs real CPU time even though it moves no game logic forward.

Why would a server flush after every packet instead of once?

Because it is the simplest thing to write: send a packet, flush, send the next, flush. It works and it is correct. It just does not scale, because a busy server sends a very large number of small packets, and each one pays the full cost of a syscall for a few bytes of payload.

Is this the same problem as garbage collection pauses?

No. GC pauses come from JVM heap and object allocation and are tuned with JVM flags, covered in the startup flags reference. Flush consolidation is about how many times the server calls into the kernel to move bytes over a socket. Different subsystem, different fix, and neither one substitutes for the other.

Can I turn flush consolidation on with a config setting?

Not directly. It's not exposed as a server.properties value or a startup flag, because it's a change to how the network code is written, not a tunable. It ships inside the server software itself. The action available to you is staying on a current Paper or Purpur build so you get netty-layer fixes as the projects land them, not configuring a value yourself.

Does this matter more with more players?

Yes, and that's the whole shape of the problem. One player generates a modest packet stream. A hundred players each generating movement, chunk, and block-update packets every tick multiplies that stream a hundredfold, and a per-packet flush multiplies its syscall cost right along with it. Consolidation flattens that curve because the flush count stops scaling with packet count.

Space NodePartner

Host Minecraft servers

Deploy a Minecraft server in under a minute. Installed, tuned and ready to play.

  • Instant deployment
  • Automatic updates
  • Ryzen CPUs
  • NVMe SSD
Deploy a serverFrom €0.90 per GB

Referenced on this site

Last reviewed 2026-08-03. Version data on this site updates automatically; this guide is reviewed by hand when the ecosystem changes.

Is this information wrong or missing something? .