Foundations · SLIs, SLOs & error budgets

SLIs, SLOs & error budgets

Three terms get used almost interchangeably in casual conversation and mean three precise, different things: the metric you measure, the target you set for it, and the contract you sign around it. This page defines each one exactly, then derives the error budget — the number that turns "how reliable should we be" from an aspiration into a spendable quantity that governs whether your team ships features or stops to fix reliability.

☺ Explain it like I'm 10

A school bus company measures how many days the bus arrives on time — that's the SLI, the actual measurement. The company's internal goal is "on time at least 99 out of every 100 school days" — that's the SLO, the target they hold themselves to. The signed contract with parents might only promise "on time at least 95 days out of 100, or we refund the month" — that's the SLA, looser than the internal goal on purpose, so a few bad days don't trigger refunds. The gap between "100 days on time" and the 99-day goal — one allowed late day per 100 — is the error budget: a deliberate, spendable allowance for things going wrong.

SLI: the thing you actually measure

A Service Level Indicator is a quantitative measurement of some aspect of the service you provide, expressed as a ratio of good events to valid events over a window of time. "The percentage of requests served in under 300ms," "the percentage of requests that return a non-5xx status code," and "the percentage of writes that are durably committed within 1 second" are all SLIs. Note the shape: an SLI is not a raw number like "average latency was 180ms" — averages hide tail behavior and give you nothing to set a target against. A proper SLI is a proportion, which is exactly what lets you later say "99.9% of requests met this bar," a statement you can grade pass/fail against a threshold.

Google's Site Reliability Engineering book (the "SRE book") formalizes this as good-events-over-valid-events: for a latency SLI you'd define "good" as requests under some threshold and "valid" as all requests eligible to be counted (excluding, say, health checks or requests from bots you've explicitly out of scope). Getting that denominator right matters as much as the threshold — an SLI that silently drops the requests that are timing out will report suspiciously good numbers precisely when things are worst.

Choosing good SLIs: measure what the user feels

The single most common mistake in SLI selection is measuring what's easy to instrument instead of what the user actually experiences. CPU utilization, queue depth, and JVM garbage-collection pause time are real signals worth alerting on operationally, but they are not SLIs, because a user doesn't care about your CPU — they care whether their request succeeded and how long it took. Good SLIs are almost always:

A background batch pipeline and a synchronous checkout API need different SLI shapes — the pipeline's user-facing promise is closer to "did the job finish by its deadline" (a freshness/correctness SLI) than "was p99 latency under 300ms," because nobody is sitting on the other end of an HTTP connection waiting for it. Pick the SLI shape that matches how the service is actually consumed; see monitoring and observability for how these get instrumented in practice.

SLO: the internal target you hold yourself to

A Service Level Objective is a target value or range for an SLI, measured over a defined window — for example, "99.9% of requests served in under 300ms, measured over a rolling 28-day window." The SLO turns a raw measurement into a pass/fail line: above the line, the service is meeting its objective; below it, it isn't. The window matters as much as the percentage — a 99.9% SLO measured over 28 days behaves very differently from the same percentage measured over a single day, because a short, sharp outage gets diluted across a longer window and takes longer to recover from in aggregate.

An SLO is internal. It's the number your team is accountable to, set collaboratively between the people who build the service and the people who depend on it, and it's revisited deliberately, not treated as physics. Setting it too high (five nines on a service that doesn't need it) burns engineering effort on marginal reliability gains instead of features; setting it too low erodes user trust before anyone notices a violation. The right SLO is the loosest one users won't notice you missing — reliability beyond that point is waste, not virtue.

SLA: the contract, and why it's looser than your SLO

A Service Level Agreement is a business contract with a customer that specifies consequences — usually financial credits or penalties — for missing a stated reliability commitment. Where an SLO is an internal target you hold yourselves to, an SLA is an external promise with teeth: miss it, and you owe someone something. Critically, a well-run SLA is set looser than the internal SLO on purpose, so the team has margin to absorb normal operational noise without triggering a customer-facing penalty. A common pattern: internal SLO of 99.9% monthly, external SLA of 99.5% — the 0.4 percentage points of slack between them is a buffer, not an accident.

That gap gives you an early-warning system for free: if you're consistently missing your SLO but still meeting your SLA, you have a real reliability problem that hasn't yet become a contractual one — the ideal moment to fix it, before a customer notices and before a credit is owed. If SLA and SLO are set identically, you've eliminated that warning window and every SLO miss is simultaneously a contract breach.

The error budget: 100% minus your SLO, spent deliberately

The error budget is the simplest idea on this page and the one with the most operational weight: it's 100% − SLO, converted into an actual quantity of allowed failure over the measurement window. A 99.9% SLO doesn't mean "never fail" — it means you are explicitly permitted to fail 0.1% of the time, and the error budget is that 0.1% expressed as real minutes, requests, or errors you're allowed to spend.

Error budget = (100% − SLO) × window

30-day window = 30 × 24 × 60 = 43,200 minutes total

99.9%  SLO  →  0.1%   of 43,200 min  =  43.2 min allowed downtime / 30 days
99.95% SLO  →  0.05%  of 43,200 min  =  21.6 min allowed downtime / 30 days
99.99% SLO  →  0.01%  of 43,200 min  =   4.32 min allowed downtime / 30 days

Each added "nine" divides the allowed downtime by roughly 10x —
and typically multiplies the engineering cost of holding that line.

The budget is not a warning to avoid — it's a resource to spend deliberately, and that reframing is the entire point of the mechanism. As long as budget remains, the team has explicit permission to take risk: ship faster, push a riskier migration, skip an extra round of canarying, run a chaos experiment against production (see chaos engineering). This is "burning" the budget — deliberately trading some of your allowed unreliability for velocity. When the budget is exhausted — the service has already used its full 43.2 minutes (or whatever the window allows) before the window closes — the policy flips: freeze new risky releases, redirect the team's priority toward reliability work, and don't resume normal release velocity until the budget starts refilling as the window rolls forward. This is "banking," and it's the mechanism that gives reliability work a legitimate, pre-agreed claim on the roadmap instead of losing every prioritization fight to the next feature.

◆ Key idea

An error budget policy only works if it's agreed before it's needed and actually enforced when it's exhausted. A team that keeps shipping risky changes through a burned-out budget "because the feature is important" doesn't have an error budget policy — it has an SLO nobody believes, and the next incident review in postmortems and blameless culture will surface exactly that gap between what was measured and what was enforced.

Putting the three together

In order: you instrument an SLI (the measurement), you set an SLO against it (the internal target), you may separately negotiate a looser SLA around it (the contractual floor), and the arithmetic gap between 100% and the SLO becomes your error budget (the spendable allowance that governs release policy). Get the SLI wrong — measuring server-side success instead of what the client actually observed, say — and every number downstream of it is measuring the wrong thing precisely. Get the SLO wrong — too tight, too loose, or measured over the wrong window — and the error budget it produces is either impossible to hold or too generous to mean anything. The whole chain is only as trustworthy as its first link.

⚠ Watch out

Don't confuse "we haven't breached the SLO yet" with "we have budget to burn." A service sitting at exactly 99.9% against a 99.9% SLO has already spent its entire budget for the window — there is zero margin left, and the correct response is the same as if you'd gone over: freeze risky changes until the window rolls forward and budget accrues again.

✓ Checkpoint

1. What's the precise difference between an SLI, an SLO, and an SLA, and why is the SLA usually set looser than the SLO? 2. A service has a 99.95% SLO measured over a 30-day window — how many minutes of downtime does its error budget allow? 3. What should a team do differently when its error budget is exhausted versus when it has budget remaining? 4. Give one example of a bad SLI and explain what makes it bad.

Check your answers
  1. An SLI is the actual measured metric (e.g. % of requests under 300ms); an SLO is the internal target set for that SLI over a defined window (e.g. 99.9% over 28 days); an SLA is an external, contractual promise with financial or business consequences for missing it. The SLA is set looser than the SLO so normal operational noise doesn't trigger a customer-facing penalty, and so a team missing its SLO but still meeting its SLA gets early warning before a contract is actually breached.
  2. 0.05% of 43,200 minutes = 21.6 minutes of allowed downtime over the 30-day window.
  3. With budget remaining, the team can ship faster and take on more release risk. With the budget exhausted, the team should freeze risky releases and shift priority to reliability work until the budget refills as the measurement window rolls forward.
  4. Any internal, resource-based metric not tied to user-visible behavior — for example, CPU utilization or JVM garbage-collection pause time. It's a bad SLI because a user doesn't experience your CPU load directly; a good SLI is measured at the boundary the user actually crosses, such as request success rate or request latency.