Skip to content
Control Plane Labs

SLOs, SLIs, and error budgets: a primer

How to pick service level indicators, set an achievable objective, calculate an error budget, and alert on burn rate instead of paging on every blip.

Ben Ennis

Published July 27, 2026

Most teams that “have SLOs” have a dashboard with a number on it and no consequences attached. That is not an SLO programme, it is decoration. The mechanism that does the work is the error budget: a specific, agreed quantity of unreliability that the team is allowed to spend, and an agreed response when it runs out. Everything else in this article exists to make that number honest.

The vocabulary comes from Google’s SRE practice, and the two canonical references are the service level objectives chapter of the SRE book and the implementing SLOs chapter of the workbook. Both are readable online for free and both are better than any vendor explainer, including this one, if you have a spare afternoon.

The three terms, precisely

An SLI is a ratio of good events to valid events, expressed as a percentage. The ratio framing matters more than it sounds: “availability” as a vague concept is unmeasurable, whereas “the proportion of HTTP requests to /api/v2/* that returned a non-5xx status within 500 ms” is a number you can compute from data you already have.

An SLO is a target for that ratio over a window: 99.9% over 28 days. Objectives without a window are meaningless, because the same failure rate can be inside or outside the target depending on how long you measure.

An SLA is a contract with financial consequences, and it is somebody else’s document. Your SLO should be tighter than your SLA, so you find out you are in trouble before your customers get a refund. The gap between the two is a deliberate margin, not an accident: if the contract promises 99.5% and you target 99.5%, then every hour of budget you spend is an hour of legal exposure, and the reliability conversation turns into a billing conversation.

The window deserves one more sentence, because the choice has consequences. A rolling 28-day window is the common default: it is four whole weeks, so weekday and weekend traffic patterns are represented equally, and it does not reset on a calendar boundary the way a monthly window does. Calendar months invite the failure mode where a team spends the last three days of a bad month waiting for the reset instead of fixing anything.

The error budget is 1 − SLO, expressed in the same window. For 99.9% over 28 days:

28 days                  = 40,320 minutes
allowed failure (0.1%)   = 40.3 minutes
99.95% over 28 days      = 20.2 minutes
99.99% over 28 days      = 4.0 minutes
99.9% over 30 days       = 43.2 minutes

Four minutes a month is the number that ends most “let us just make it four nines” conversations. A single unlucky rolling restart spends the entire monthly budget. The SRE book’s availability table lists these conversions if you want them for other windows.

Choosing an SLI that survives contact with reality

Three properties make an SLI useful, and dropping any one of them produces a metric that gets ignored within a quarter.

It correlates with user experience. CPU utilization is not an SLI. Queue depth is not an SLI. Neither is up/down from a single external prober, because a service can answer a health check while every real request fails. The monitoring distributed systems chapter makes the same argument at length: measure the thing the user notices.

It is measured where the user is. Server-side metrics miss the failures that never reached your server, including DNS, TLS handshake failures, and load balancer 502s emitted before your application saw the request. Load-balancer logs are usually the best available proxy; real client telemetry is better and harder.

It has a clear denominator. “Valid events” needs a definition. Do you count health checks? Requests from your own CI? Requests that were rejected as malformed, where the failure is the client’s? Write the answer down, because every future argument about whether an incident counted will be an argument about the denominator.

For request-driven services, the four SLI shapes worth considering are availability (proportion of successful requests), latency (proportion of requests faster than a threshold), quality (proportion served without degradation), and freshness (proportion of data younger than a threshold). Pipelines and batch systems mostly use the last two.

Latency SLOs are threshold-based, not average-based

Do not write a latency SLO as “p99 under 500 ms”. Write it as “99% of requests complete in under 500 ms over 28 days”. They sound identical and they behave differently: the first is a percentile of a distribution you then have to average over time, and averaging percentiles is not a valid operation. The second is a ratio of good events to valid events, which composes correctly over any window.

This also sidesteps a real measurement problem. Prometheus histograms compute quantiles by interpolating within buckets, so a histogram_quantile result is only as accurate as your bucket boundaries — the Prometheus histogram documentation is explicit about this, and about the fact that averaging or summing quantiles across instances produces a meaningless number. Counting requests under a threshold requires only that a bucket boundary sits at your threshold, which is a much weaker requirement:

# Good events: requests faster than 500ms, over 28 days
sum(rate(http_request_duration_seconds_bucket{le="0.5",job="api"}[28d]))
/
sum(rate(http_request_duration_seconds_count{job="api"}[28d]))

Pick your SLO thresholds first, then set your histogram buckets to include them. Doing it the other way round means your SLO is defined by whatever bucket boundaries a library author chose.

Alerting on burn rate, not on breaches

The naive alert — “page when the error rate exceeds 0.1%” — is unusable. It fires on every transient blip and stays quiet during a slow burn that will blow the budget in three days. The fix, from the workbook’s alerting on SLOs chapter, is to alert on burn rate: how fast you are consuming the budget relative to the rate that would exactly exhaust it over the window. A burn rate of 1 spends the whole budget exactly at the end of the period. A burn rate of 14.4 spends 2% of a 30-day budget in an hour.

The workbook’s recommended starting configuration for a 99.9% SLO uses multiple windows at different burn rates:

Severity  Long window  Short window  Burn rate  Budget consumed
page      1 hour       5 minutes     14.4       2%
page      6 hours      30 minutes    6          5%
ticket    3 days       6 hours       1          10%

Both windows must be violated for the alert to fire. The short window — one twelfth of the long window — exists to make the alert reset quickly once the problem stops, instead of staying lit for the remainder of the long window. This is the single highest-value change most teams can make to their paging setup: it cuts false pages sharply while catching slow burns that threshold alerts miss.

Implement it with recording rules rather than computing multi-window ratios in the alert expression, because the query cost of a 3-day window evaluated every 15 seconds is not trivial. Prometheus’ recording rules documentation covers the mechanics.

The error budget policy is the actual deliverable

An error budget with no policy attached is a metric. A policy states, in advance and in writing, what happens when the budget is exhausted. The workbook’s error budget policy chapter gives a template; the parts that matter are these.

Who decides. Name a role, not a committee. The person on call should be able to invoke the policy without scheduling a meeting.

What stops. The usual answer is that feature releases pause and reliability work takes priority until the trailing window is back inside the objective. Being specific matters: does a security patch ship during a freeze? Does a config change? Write it down before you need the answer.

What counts. Planned maintenance, load tests, and incidents caused by a dependency all need a decided treatment. The honest default is that they count, because your users experienced them. Carve-outs are how SLO programmes become theatre.

Who can grant an exception, and how visible that decision is. Exceptions are inevitable. Silent exceptions are corrosive.

Four ways these programmes fail

The objective is aspirational. Someone picks 99.99% because it sounds serious, the service delivers 99.5%, and within two months the burn-rate alerts are muted because they fire constantly. An objective the service cannot hit produces exactly one outcome: the alerts get ignored, and so does the budget.

The SLO measures the wrong layer. A budget defined on your service’s own error rate will show green through an outage in a dependency that returns plausible-looking empty results. If a downstream failure is invisible in your SLI, your SLI is measuring your code rather than your users’ experience.

Every service gets an SLO. Internal components with no direct user traffic usually do not need one. Their reliability shows up in the SLO of the user-facing service they support, and giving each one an independent objective multiplies the alerting surface without adding information.

Nobody owns the number. If the budget is exhausted and nothing changes, the programme is over — everyone learns the number is advisory, and the next conversation about reliability starts from zero. This is why the policy matters more than the dashboard.

Getting started without a six-month project

Pick one user-facing service. Define one availability SLI from load balancer logs and one latency SLI with a threshold you can defend. Set the objective at roughly your trailing 30-day performance, not at an aspirational number — an SLO you are already failing tells you nothing, and one you cannot fail tells you less. Run it for a month with no alerting attached and see whether the number moves when users complain. If it does not, the SLI is wrong; fix that before building anything on top of it.

Then add burn-rate alerts, then write the policy. Only then consider a second service. Teams that start by defining forty SLOs across every service produce forty numbers nobody looks at.

If you want a vendor-neutral way to express these definitions in code, OpenSLO is a YAML specification for SLOs with an open-source repository and support in several tools; Google Cloud documents its own model in the SLO monitoring guide. Either is better than a wiki page, because a definition in version control can be reviewed when someone changes it.

The bottom line

The SLO is not the point. The point is having a pre-agreed, quantified answer to “is this good enough, and what do we do if it is not”. A team with one honest SLI, a realistic objective, burn-rate alerts, and a written policy is in better shape than a team with a wall of dashboards and no agreement about what they mean. Pair the practice with blameless postmortems — the SRE book’s postmortem culture chapter is the reference — because a budget that gets spent teaches you something only if somebody writes down what it bought.

Frequently asked questions

What is the difference between an SLA and an SLO?+
An SLA is a contractual promise to a customer with a penalty attached. An SLO is your internal target and should be stricter, so you detect problems before you owe anyone money. Do not publish your SLO as your SLA.
How many nines should we aim for?+
As few as your users will accept. 99.99% over 28 days leaves about four minutes of failure budget, which one bad deploy can consume. Start from your current trailing performance and tighten only when there is a real user complaint driving it.
Should planned maintenance count against the error budget?+
By default, yes — the user experienced downtime regardless of whether you scheduled it. If you carve out maintenance windows, do it explicitly in the error budget policy and keep the list short, or the objective stops describing reality.
Why alert on burn rate instead of on the SLO being breached?+
Because by the time the objective is breached, the budget is already gone. Burn-rate alerts from the SRE workbook fire while you can still act, and the multi-window form suppresses the transient blips that make error-rate thresholds unusable.
Can we use p99 latency as an SLI directly?+
Prefer a threshold ratio: the proportion of requests faster than 500 ms. Percentiles cannot be averaged across time or instances, and Prometheus histogram quantiles are interpolated estimates that depend on bucket layout.

Tags: #sre, #slo, #observability, #alerting