The Shortest Stave: What Liebig's Law of the Minimum Teaches About Distributed Systems

The Shortest Stave: What Liebig's Law of the Minimum Teaches About Distributed Systems

June 22, 2026

TL;DR: A barrel made of staves of different lengths holds only as much water as its shortest stave allows. That’s the law of the minimum — growth is capped by the scarcest resource, not the sum of all resources. It governs my planted aquariums (one missing nutrient stalls everything) and my Kubernetes homelab (one saturated datastore pins the whole control plane). It’s the same idea behind Amdahl’s law and the Theory of Constraints. And, fittingly, the “law” most people call Liebig’s wasn’t actually Liebig’s.


I keep two systems alive. One is a planted aquarium — light, CO₂, nitrogen, phosphorus, a dozen trace elements, all in balance. The other is a Kubernetes cluster — CPU, memory, a datastore, a network, a stack of operators, all in balance. For years I treated these as opposite hobbies. They aren’t. They’re governed by the same law, written down 200 years ago for soil.

In this post I’ll cover:

  • The law of the minimum — the barrel, the shortest stave, and why it isn’t really “Liebig’s law”
  • Redfield’s extension — why adding more of the wrong resource doesn’t help, it just creates waste
  • The same law in systems — the bottleneck, and a real example from my own homelab
  • The practical takeaway — how to find the shortest stave instead of lengthening the wrong one

The law of the minimum

In plant nutrition there’s a principle so foundational it’s usually taught with a picture: a wooden barrel whose staves are all different lengths. Fill it with water and it doesn’t matter how tall the longest staves are — the water pours out at the height of the shortest one. A plant’s growth is limited by the single nutrient in shortest supply, no matter how abundant everything else is. Drown it in nitrogen, potassium, and light; if it’s short on iron, it stops at iron.

Here’s the thing almost everyone gets wrong, including textbooks: it’s commonly called Liebig’s law of the minimum, but Justus von Liebig didn’t discover it. The German botanist Carl Sprengel formulated the principle around 1828, more than a decade before Liebig popularized it in the 1840s. Liebig was the great communicator of 19th-century agricultural chemistry, so the idea took his name — a clean example of the Matthew effect, where credit accretes to the already-famous. There’s even a long-running scholarly argument titled, literally, “Liebig or Sprengel?” The most cited law in plant nutrition is misattributed.

(I’ll resist the urge to relitigate every attribution claim floating around — some accounts push the origins further back still. The well-documented version is simple: Sprengel formulated it, Liebig made it famous.)

Why open a systems post with botanical history? Because the misattribution is a small lesson in itself: the loudest name in the room isn’t always the source of the insight. Hold that thought — it comes back when we talk about debugging.

Redfield’s extension: more of the wrong thing is just waste

Decades later, the oceanographer Alfred Redfield sharpened the idea. Studying plankton, he noticed that limiting one element doesn’t change the composition of the organisms — it reduces the total biomass the system can sustain, right up until the limiting element runs out. In other words: the bottleneck doesn’t reshape the output, it caps the quantity of it.

Any planted-tank keeper learns the practical, painful version of this. If your plants are limited by, say, CO₂, then dosing more nitrate and phosphate doesn’t grow more plants. It grows algae. The surplus nutrient the plants can’t use because they’re stuck on the real limiter doesn’t vanish — it feeds whatever else is waiting. More of the non-limiting resource isn’t neutral. It’s actively harmful.

Sit with that, because it’s the part engineers get wrong most often.

The same law, wearing a Kubernetes T-shirt

Now swap the barrel staves for system resources: CPU, memory, disk IOPS, network bandwidth, connection-pool slots, a single-writer datastore. Throughput is capped by the one that saturates first. Everything else is a long stave doing nothing.

I learned this the loud way. I recently wrote up an incident where my k3s control plane was pinned at 99% CPU, load average 79 on 8 cores. My instinct was to look at the busy resources — the operators hammering the API, the audit loops, the autoscaler checkpoints. I disabled them one by one and measured. CPU moved by noise.

The shortest stave wasn’t any of the loud consumers. It was the datastore — SQLite behind a single-writer shim, unable to compact fast enough. Every other resource was a tall stave. Adding CPU wouldn’t have helped; cutting individual API clients didn’t help; the system was limited at exactly one place, and until I lengthened that stave (by moving to etcd), nothing else mattered. The loud components were Liebig — famous, attention-grabbing. The quiet datastore was Sprengel — the actual cause.

This is not a homelab quirk. It’s a law with many names:

  • Amdahl’s law: the speedup from parallelizing is capped by the fraction you can’t parallelize. The serial part is your shortest stave.
  • The Theory of Constraints (Goldratt): every system has exactly one binding constraint at a time; improving anything that isn’t the constraint is, at best, wasted effort.
  • Queueing theory: latency explodes at the single most-utilized resource, regardless of slack everywhere else.

flowchart LR
    A[CPU: plenty] --> T{Throughput}
    B[Memory: plenty] --> T
    C[Network: plenty] --> T
    D[Datastore: SATURATED] --> T
    T --> O[Output capped by D
everything else idles]

They’re all the barrel. One limiting factor sets the level for the whole system.

The takeaway: find the shortest stave, don’t lengthen the wrong one

Two practical habits fall straight out of this.

First: measure to find the constraint — don’t guess. The shortest stave is rarely the loudest component. In my incident, the things screaming for attention (high-CPU operators) were innocent; the quiet thing (the datastore) was the limit. The whole discipline of profiling, tracing, and load-testing exists to answer one question: which stave is shortest right now? Answer that before you touch anything.

Second: lengthening a non-limiting stave is worse than useless — it’s the algae problem. Throwing CPU at a datastore-bound system doesn’t add throughput; it adds cost, complexity, and new failure modes, exactly like dosing nutrients into a CO₂-limited tank grows algae instead of plants. Redfield’s point in an SRE context: capacity you add away from the constraint doesn’t become performance. It becomes waste — and often a new thing to debug.

And once you fix the binding constraint, the law doesn’t retire. It just moves. Lengthen the shortest stave and a different one becomes shortest. A balanced aquarium and a healthy cluster are both the same ongoing act: continuously finding the current limiter and addressing it, knowing a new one will take its place. Stability isn’t a finish line. It’s the practice of always knowing your shortest stave.

That’s the strange gift of keeping a planted tank while running a homelab. The tank taught me to stop staring at the tall, healthy, obvious staves and go looking for the short one I’d rather not find. It’s the most useful debugging instinct I have — and I got it from a barrel.