A system design interview guide to predicting when you will run out of hardware — turning utilization telemetry into a demand forecast, a buffer policy, and a procurement order that lands before the wall does.
Fleets do not run out of capacity suddenly; they run out predictably, and the failure is almost always organizational rather than technical — nobody ordered the machines in time. Hardware has a long lead time: you cannot conjure a rack the day you need it, so you must see the shortfall coming weeks or months ahead and place the order early. A capacity forecasting system is the machine that makes that foresight routine. It ingests utilization telemetry, models future demand from trend, seasonality, and known growth, translates that demand into hardware and dollars, applies a headroom policy so you never run to the edge, and alerts — with enough runway — when a resource is projected to exhaust. This guide is infra-economics flavored: the output is not a dashboard, it is a purchase order placed at the right time.
The system’s job is to answer one question reliably: for each resource, when will demand exceed supply, and what should we buy to prevent it? Everything else serves that.
The numbers here are about horizons and lead times, because those set how far ahead the forecast must see and how early the alert must fire.
| Quantity | Assumption | Result |
|---|---|---|
| Telemetry cadence | utilization sampled every 1–5 min | plenty of history; downsample to hourly/daily for modeling |
| Series count | resource × service × region × HW type | tens of thousands of forecastable series |
| Planning horizon | forecast 2–4 quarters ahead | needs 1–2 years of history to learn seasonality |
| Procurement lead time | order → racked & serving | weeks to months — the number that matters most |
| Headroom buffer | N+2 / keep ~20–30% free | absorb spikes + one failure domain |
| Alert runway | fire before exhaustion by | ≥ lead time + safety margin |
The controlling number is procurement lead time. It defines the alert runway: if hardware takes eight weeks to arrive, a projected-exhaustion alert that fires four weeks out is useless. The whole system exists to convert a slow physical process (buying and racking machines) into a timely one by seeing far enough ahead.
A shared vocabulary keeps the design honest, especially around what “capacity” and “headroom” actually mean.
| Term | Meaning |
|---|---|
| Demand | Forecasted resource need over time — what the workload will consume. |
| Supply / capacity | Provisioned resource available — what the fleet can serve. |
| Headroom | Free capacity above current demand — the safety margin. |
| Buffer policy | The rule for how much headroom to keep (e.g. N+2, or 25% free). |
| Days-to-exhaustion | Time until forecasted demand crosses the usable-capacity line. |
| Lead time | Delay from ordering hardware to it serving traffic. |
| Order point | The moment you must order so hardware lands before the buffer is breached. |
The core relationship: order point = exhaustion date − lead time − safety margin. The forecast’s only real purpose is to compute that date early enough to act on it.
The system is a pipeline from raw telemetry to a procurement decision, with a planning loop hanging off the middle for what-if analysis.

Forecasting demand starts by recognizing that a utilization time series is not random — it is a few structured components plus noise. Decompose it, model each part, and recombine.

Classic model choices: Holt-Winters (exponential smoothing with trend and seasonality) is simple and robust; ARIMA / SARIMA handles autocorrelation and seasonality with more rigor; Prophet is convenient for series with strong seasonality and holiday effects and tolerates gaps. The key output is not a single line but a distribution: forecast at P50 for the expected case and at P90 for planning, because you provision against a pessimistic percentile, not the average. You buy for the bad month, not the typical one.
for series in resources:
hist = store.history(series, window="2y")
parts = decompose(hist) # trend + seasonality + residual
model = fit(parts, extra=known_events) # inject launches/migrations
fc = model.forecast(horizon,
quantiles=[0.5, 0.9]) # plan against P90
publish(series, fc)
A forecast of demand only becomes actionable when compared to supply through a headroom policy. You never plan to fill capacity to 100% — you keep a buffer for spikes, for a failed failure-domain, and for the forecast’s own error.

The buffer policy encodes the safety margin: N+1 or N+2 (survive one or two failure domains going down at peak), or a simple “keep 25% free.” Usable capacity is provisioned capacity minus the buffer, and the alert fires when the forecast — not current usage — is projected to cross that usable line within the lead-time runway. Alerting on the projection rather than the present is the whole point: by the time current usage hits the wall, it is far too late to order.
usable = capacity - buffer(policy) # e.g. N+2 or 25% free
exhaustion_date = first_day(forecast.p90 > usable) # pessimistic percentile
order_point = exhaustion_date - lead_time - margin
if today >= order_point:
alert("procure now", resource, exhaustion_date, units_needed) # runway preserved
The forecast is a baseline; the value multiplies when planners can perturb it and when its output flows straight into the buying process.
Forecasting trades the cost of being wrong in one direction against the cost of being wrong in the other, and the design is mostly about choosing which error to prefer.
A capacity forecasting system converts slow physical procurement into timely action by seeing demand far enough ahead. Its deliverable is a well-timed order, and every part of the design serves the order point.
| Concern | Mechanism |
|---|---|
| What do we feed the model? | Cleaned, downsampled utilization/growth telemetry with 1–2 years of history. |
| How do we model demand? | Decompose into trend + seasonality + growth; fit Holt-Winters / ARIMA / Prophet. |
| What do we forecast against? | A pessimistic percentile (P90) with uncertainty bands — provision for the bad case. |
| How much slack do we keep? | A headroom buffer (N+2 or ~25% free) subtracted from provisioned capacity. |
| When do we alert? | When the forecast (not current usage) is projected to breach the buffer within the runway. |
| How early must the alert be? | At least procurement lead time plus a safety margin — the order point. |
| How do we plan changes? | What-if scenarios re-run the forecast; output translates to hardware and cost. |
| How does it drive action? | Integration with procurement and finance turns alerts into orders and capex plans. |