SLOs, SLIs, and Error Budgets: The Math Behind SRE Decision-Making
How Service Level Indicators, Objectives, and error budgets turn 'be reliable' into a concrete, measurable number that actually drives engineering decisions.
“Make it more reliable” is not an engineering target — it’s a feeling. The entire point of SLIs, SLOs, and error budgets, as formalized by Google’s SRE practice, is converting reliability from a vague aspiration into a specific number that can be measured, tracked, and used to make concrete trade-off decisions between shipping features and investing in stability.
SLI: the actual measured signal
A Service Level Indicator is a precisely-defined, directly measured metric of service behavior — not a vague notion of “is it working,” but a specific ratio: successful requests over total requests, or requests served under some latency threshold over total requests.
SLI = (successful requests) / (total valid requests)
sum(rate(http_requests_total{status!~"5.."}[5m]))
/
sum(rate(http_requests_total[5m]))
Precision matters here — “successful” needs an exact definition (which status codes count, does a client-side timeout count against you, does a request to a health-check endpoint count at all), since a sloppily-defined SLI produces a number that doesn’t actually correspond to what users experience.
SLO: the target you’re accountable to
A Service Level Objective is a target value for an SLI over a defined window — “99.9% of requests succeed, measured over a rolling 30 days.” This is the number a team is actually accountable to, and it should be set based on what users genuinely need, not on what feels impressive: a 99.99% SLO for a service where 99.9% would fully satisfy users just burns engineering effort chasing reliability nobody’s asking for.
slo:
name: api-availability
target: 0.999
window: 30d
Error budget: the SLO’s most important consequence
If the SLO is 99.9% success over 30 days, the error budget is the remaining 0.1% — a concrete, spendable allowance of acceptable failure. Over a 30-day window, 0.1% works out to roughly 43 minutes of full downtime (or an equivalent amount of partial degradation) that’s already accounted for as acceptable.
Error budget = (1 - SLO) × total requests (or total time)
99.9% over 30 days ≈ 43.2 minutes of allowed downtime
99.95% over 30 days ≈ 21.6 minutes
99.99% over 30 days ≈ 4.3 minutes
What the error budget is actually for: a decision-making tool
The entire point of quantifying an error budget is using it to arbitrate a real, recurring tension: ship new features and take on risk, or slow down and invest in reliability. The policy is simple and mechanical once established: while there’s budget remaining, ship normally; once the budget is exhausted, feature work pauses and reliability work takes priority until the budget recovers.
if error_budget_remaining > 0:
proceed with normal release velocity
else:
freeze non-critical releases; prioritize reliability fixes
This is what makes error budgets genuinely different from just “try to minimize downtime” — they give a team explicit, pre-agreed permission to take risks (deploy more aggressively, run chaos experiments, ship experimental features) as long as the budget allows it, rather than reliability being an unquantified, permanently risk-averse instinct that slows everything down all the time.
Burn rate: how fast you’re spending the budget
Burn rate measures how quickly the error budget is being consumed relative to the window — a burn rate of 1x means you’ll exhaust the budget exactly at the end of the window (right on target); a burn rate of 10x means you’ll exhaust a 30-day budget in 3 days, which is precisely the kind of signal that should page someone immediately rather than waiting for the SLO itself to be breached.
(1 - (sum(rate(http_requests_total{status!~"5.."}[1h])) / sum(rate(http_requests_total[1h]))))
/ (1 - 0.999)
Multi-window burn-rate alerts (checking both a short window for fast-moving incidents and a longer window to avoid noisy false alarms from brief blips) are the standard alerting pattern built directly on top of this math.
Choosing an SLO that isn’t arbitrary
A good SLO reflects actual user impact and business reality, ideally derived from historical performance and genuine user expectations rather than picked as a round, “impressive-sounding” number. Setting an SLO tighter than users actually need — or tighter than the system has ever historically achieved — just guarantees a permanently exhausted error budget and a team stuck in perpetual reliability-freeze mode for a target nobody was actually asking for.
Why this framework has become standard SRE practice
The genuine innovation isn’t measuring uptime — teams have always done that — it’s converting reliability into a budget that’s explicitly allowed to be spent, giving engineering organizations a shared, numeric, pre-negotiated answer to “can we ship this risky thing right now” instead of that question being an ad hoc, often political argument between product and engineering every single time it comes up.