Hyrum’s Law: Why Every Observable Behavior of Your API Becomes Someone’s Dependency josedacruz, August 17, 2026August 17, 2026 TL;DR: Hyrum’s Law says that if enough people use your software, every observable behavior of it — not just the parts you documented and promised — will eventually become something someone depends on. That means “we never promised that” is not the same as “it’s safe to change.” This post explains the idea in plain terms, walks through a concrete example, and gives you a few practical habits that make it less painful. What is Hyrum’s Law, in plain terms? Hyrum’s Law is named after Hyrum Wright, a Google engineer, and it’s usually written like this: “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.” Translated into everyday language: if your code does something, and enough people can see it doing that something, someone will eventually build on top of it — even if you never said they could. An “API” here just means any interface other code or people call into: a REST endpoint, a function signature, a database schema, a config file format, even a CLI tool’s log output. The word “contract” means the rules you officially promised to follow, usually written down in documentation. The uncomfortable part of the law is the word “all.” Not just the documented behaviors. All of them, including the ones you consider bugs, accidents, or implementation details you never meant to expose. Why does this happen even when the documentation is clear? Because most developers don’t read documentation as carefully as they read actual behavior. When someone is trying to get their code working today, they don’t ask “what does the spec say I’m allowed to rely on?” They ask “what does this thing actually do right now?” — and then they write code against that. This isn’t laziness. It’s just how integration work happens under a deadline. If your API returns JSON keys in a certain order, and a developer’s script happens to work because of that order, they will ship it that way, whether or not you ever promised key ordering. Multiply that by thousands of API consumers, each quietly leaning on a slightly different accidental detail, and you get a huge invisible surface area of things you can no longer safely change. Can you walk through a concrete example? Picture a small team building an internal “Orders” API for an e-commerce platform. The documented contract says: “GET /orders/{id} returns an order object with id, status, and total.” Under the hood, the API is built on top of an ORM (a library that turns database rows into objects automatically), and it happens to also return a few extra fields nobody asked for: created_at, internal_warehouse_id, and a debug field called _shard. None of these are documented. They’re just leftovers from how the ORM serializes objects. Six months later, the mobile team wants to show “time since order placed” in the app, so they start reading created_at straight off that same response, because it’s right there and it works. The fulfillment team’s internal dashboard starts filtering by internal_warehouse_id because it’s convenient. Nobody asks the Orders team first, because nothing about the response looked off-limits. Now the Orders team wants to swap out the ORM for a faster, hand-written query layer. The new version doesn’t include _shard or internal_warehouse_id at all, since those were never meant to be public. The moment it ships, the fulfillment dashboard breaks in production, and nobody on the Orders team saw it coming — because as far as they knew, they never promised those fields existed. That’s Hyrum’s Law happening in real time. The fields were never in the contract. They were observable. That was enough. How an accidental behavior quietly becomes part of your real contract. Does this mean I can never change anything? No, but it does mean you should stop assuming “undocumented” equals “safe to break.” In practice, the risk isn’t evenly spread. A behavior used by one internal script is a very different risk than a behavior baked into a mobile app on a million phones that can’t be force-updated. The goal isn’t to freeze your system forever — it’s to be honest with yourself about which behaviors are actually load-bearing, even if you never intended them to be. Teams that ignore this usually find out the hard way, during an incident, exactly which “implementation detail” someone was secretly relying on. Teams that plan for it find out ahead of time, on their own schedule, which is a much better place to be. How do I protect myself from this as an API or system designer? A few habits go a long way: Only return what you mean to promise. Don’t let a serialization library or a database query dump its raw shape straight into a public response. Build an explicit response model, even if it feels like extra boilerplate at first. Add deliberate randomness or variation where it’s safe to. Some teams intentionally shuffle non-guaranteed ordering, or rotate values that shouldn’t be relied on, specifically so nobody can quietly depend on an accident. If it never stays the same, nobody can anchor to it. Version your contract, and mean it. A versioned API (like /v1/orders vs /v2/orders) gives you a place to make breaking changes on purpose, with warning, instead of by surprise. Log and monitor unexpected usage patterns. If you can see which fields or endpoints are actually being hit and how, you can find hidden dependents before you break them, not after. When in doubt, ask before you assume a field is “just internal.” If it’s visible in a response that leaves your system, treat it as a promise until proven otherwise. Isn’t this just a fancy way of saying “maintain backward compatibility”? It’s related, but it’s a stricter and more uncomfortable version of that idea. “Maintain backward compatibility” usually means “honor what we documented and promised.” Hyrum’s Law says that’s not enough, because your users don’t read the promise — they read the behavior. Backward compatibility is about keeping your word. Hyrum’s Law is about the fact that people will build on your actions whether or not you gave your word at all. That’s why experienced API designers get nervous about phrases like “that’s just an implementation detail, it’s fine to change.” Fine according to the contract, maybe. Fine according to the people actually depending on it in production? Only one way to find out, and it’s usually a bad way. Where else does this show up besides public APIs? Almost anywhere one system or person depends on another. A few common places: Internal libraries. A helper function’s exact error message gets parsed by a script somewhere, and now you can’t reword the message without breaking that script. Database schemas. A column that was only ever meant for internal bookkeeping gets read directly by a reporting tool, and suddenly you can’t rename it without a coordinated migration. Log formats. Ops teams write alerting rules against the exact wording of a log line. Change the wording to make it clearer, and you silently break their alerts. CLI tools. Someone scripts around your command’s plain-text output because there was no structured output option. Now your “just improve the formatting” change is a breaking change for them. The pattern is always the same: something was never meant to be a promise, it was simply visible, and visibility was enough for someone to build on it. What’s the one habit worth taking away from this? Before you ship anything another system or person can observe, ask yourself: “if this behavior stayed exactly this way forever, would that be okay?” If the honest answer is no, either hide it, randomize it, or explicitly document it as unstable. Silence is not protection. The moment something is observable, Hyrum’s Law is already quietly at work, whether your documentation mentions it or not. Related architecture API Designbackward compatibilityheuristicshyrum's lawsystems thinking