Engineering Culture

Hyrum's Law: Every Behavior Becomes a Contract

With enough users, people depend on every observable behavior of your system, including the bugs. Your real API is bigger than the one you documented.

RE

CEO, Ruzora

Updated 8 min read

Hyrum's Law says: "With a sufficient number of users of an API, it does not matter what you promise in the contract: all observable behaviors of your system will be depended on by somebody" (hyrumslaw.com). It comes from Hyrum Wright, who worked on large-scale code changes at Google, and Titus Winters gave it the name.

In practice it goes like this. You document an API, promise a contract, and assume you're free to change anything you didn't promise. Then you change an internal detail and something breaks three teams away.

Key Takeaways

  • Hyrum's Law: with enough users, all observable behaviors of your system will be depended on, regardless of your documented contract (Hyrum's Law).
  • That includes timing, ordering, error messages, and outright bugs (Laws of Software).
  • Practically, there is no private implementation once usage is large enough.
  • It came from Hyrum Wright's experience doing large-scale infrastructure migrations at Google.

The Law

Hyrum Wright's formulation is precise: with a sufficient number of users of an API, it does not matter what you promise in the contract, all observable behaviors of your system will be depended on by somebody (Hyrum's Law). The law came out of his work on low-level infrastructure migrations at Google, where changing a seemingly trivial detail in a library would break distant systems nobody knew were coupled to it.

The key word is observable. Your documented contract might say "returns a list of users." But if that list has always come back sorted, someone is depending on the sort order. If an error message has always contained a particular string, someone is parsing it. If a call has always taken under 50 milliseconds, someone's timeout depends on it. None of that is in the contract. All of it is now load-bearing.

Bugs Become Features

The most uncomfortable corollary: even your bugs become dependencies (Hyrum's Law explained). If a function has always returned an off-by-one result and consumers have quietly compensated for it, fixing the bug breaks them. This is why large systems end up with "bug-for-bug compatibility," where correct behavior means whatever the old version did, mistakes included. The gap between your documented interface and your actual, implicit interface widens with every user.

What you documentedWhat people actually depend on
Returns a listThe order it comes back in
Returns an errorThe exact error message text
Returns a valueHow long it takes
The specified behaviorThe bugs, too

Remote roles for backend and platform engineers. If you are the person who gets paged when an "internal" change breaks a consumer, Ruzora is hiring remote engineers from LATAM for US teams: Node.js Backend Engineer (NestJS), Go Backend Engineer, Java Backend Engineer (Spring Boot) and Platform / SRE Engineer.

A Concrete Version

A team owns an internal API that returns search results. The docs say nothing about ordering, so when they swap the underlying index for a faster one, they consider it a safe, invisible change. Two days later a billing report is wrong, because a downstream team had been taking the first result and assuming it was the most recent, since it always had been. Nobody documented that assumption, nobody promised it, and it was still real. The "internal implementation detail" was a contract the whole time.

What to Do About It

Hyrum's Law is a fact of gravity rather than a problem to solve, so the response is defensive. Make the behavior you don't want depended on hard to depend on: randomize what should be unordered, so nobody can rely on an accidental order. Keep interfaces small, since fewer observable behaviors mean fewer implicit contracts. Version deliberately, and treat any change to widely-used code as a change to an implicit interface you can't fully see, which is exactly why Chesterton's Fence applies so strongly to shared code. And where you can, measure who's actually calling what before you change it.

The Honest Counterpoint

Taken too far, Hyrum's Law becomes an excuse to never change anything, which calcifies a system just as surely as reckless changes break it. The law describes systems with enough users, and most internal code doesn't have that many. A service with three known consumers is a different problem from a library with ten thousand, and treating them the same wastes enormous effort. The useful reading is proportional: the bigger the blast radius, the more you should assume undocumented behaviors are load-bearing, and the more you should invest in deprecation paths over clean breaks.

What This Means for Teams

Hyrum's Law is one of those things engineers learn by breaking production once, and it shapes how carefully someone treats shared code. Senior engineers instinctively ask "who depends on this, and what have they noticed about it?" before changing a widely-used interface, which is the same understand-before-you-change judgment that makes legacy work safe. That instinct is hard to teach and easy to test for, and it's part of what we screen for in how to verify a senior engineer. See available engineers.

Frequently Asked Questions

What is Hyrum's Law?

Hyrum Wright's observation that with enough users of an API, every observable behavior of your system will be depended on by someone, regardless of what your documented contract promises.

Does that include bugs?

Yes. Consumers compensate for buggy behavior, so fixing the bug breaks them. This is why large systems end up with "bug-for-bug compatibility," where correct behavior means whatever the old version did.

How do I protect against it?

Make undesirable dependencies hard to form: randomize what should be unordered, keep interfaces small, version deliberately, and measure who actually calls what before changing widely-used code.

Does it apply to small internal services?

Less so. The law describes systems with enough users. A service with three known consumers is a much smaller problem than a library with thousands, so scale your caution to the blast radius.

The Bottom Line

Your real interface is bigger than the one you wrote down: with enough users, the ordering, the timing, the error strings, and even the bugs become contracts someone depends on. Treat changes to widely-used code as changes to an invisible interface, make accidental dependencies hard to form, and scale your caution to how many people could break.

Engineers: if you have lived through a migration where Hyrum's Law bit, see the open Go backend, Node.js backend and platform / SRE roles.

Roberto Espinoza is CEO of Ruzora, which helps US startups hire pre-vetted senior LATAM engineers, with a vetted shortlist in 72 hours. See available engineers.

RE

CEO, Ruzora

Roberto is the founder and CEO of Ruzora. He works directly with US startup founders and CTOs on staff-augmentation and software-factory engagements, and personally reviews senior engineer placements.

Senior LATAM engineers

Get a vetted shortlist within 72 hours.

Tell us the role and the stack. Within 72 hours you're reviewing a vetted shortlist of senior LATAM engineers who match it.