Education › DevOps › Stage 4: Operate & secure

Measuring delivery with DORA metrics

Deployment frequency, lead time, change failure rate, time to restore — and how to improve them.

Advanced ~25 min read Module 16 of 17

Everything in this track, from small pull requests to pipelines to GitOps, is supposed to make delivery faster and safer. How do you know whether it is working? The DORA research programme has studied software teams for over a decade and identified a small set of metrics that reliably distinguish high-performing teams, and that predict organisational outcomes. This module explains what they measure, how to compute them from data you already have, and how to improve them without turning them into targets that people game.

After this module you can
  • Define the four key DORA metrics and explain why throughput and stability rise together
  • Compute each metric from deployment and incident records you already have
  • Diagnose which constraint a poor metric points at, and choose the right improvement
  • Use the metrics to guide a team's improvement without turning them into individual targets
  • Recognise common ways the metrics are gamed or misread

The four keys

DORA stands for DevOps Research and Assessment, the group behind the annual State of DevOps reports and the book Accelerate. Its central finding is a set of four metrics, in two pairs.

MetricMeasuresQuestion it answers
Deployment frequencyThroughputHow often do we release to production?
Lead time for changesThroughputHow long from a commit to that commit running in production?
Change failure rateStabilityWhat fraction of deployments cause a failure that needs remediation?
Time to restore serviceStabilityWhen a deployment fails, how long until service is restored?

The research's most important result contradicts a deeply held intuition: speed and stability are not a trade-off. The teams that deploy most often are also the ones with the lowest failure rates and fastest recovery. The cause runs in one direction. Deploying often forces changes to be small, and small changes are easy to review, easy to test, unlikely to fail, and quick to diagnose and revert when they do. Large, infrequent releases bundle hundreds of changes, so something always breaks, and finding it takes a long time.

Recent reports have refined the stability measures, renaming time to restore as failed deployment recovery time and adding a measure of unplanned rework. They have also discussed reliability, meaning whether a service meets its operational targets, as a related outcome. That last one is the subject of the SRE track. The exact benchmark figures shift from year to year, so read the current report for them and do not memorise numbers.

Note

The metrics describe a team and a service, not individual people. Used per person they measure nothing meaningful and cause real harm.

Computing them from data you already have

You need only two kinds of event. A deployment record has a service, a timestamp, the commit that was deployed and, ideally, whether it later needed remediation. An incident record has a start time, a restore time and, where known, the deployment that caused it. Your pipeline and your incident tool already produce both.

text
deployment frequency   = production deployments / time period

lead time for changes  = median( deploy time - commit time )
                         over every commit included in each deployment

change failure rate    = deployments needing remediation / total deployments
                         (remediation = rollback, hotfix, forward fix, patch)

time to restore        = median( restored time - failure start time )
                         over failures caused by a change
With a deployments table and an incidents table
sql
-- deployment frequency: deployments per week, per service
SELECT service, date_trunc('week', deployed_at) AS week, count(*) AS deployments
FROM deployments
WHERE environment = 'production'
GROUP BY service, week
ORDER BY week;

-- lead time for changes: median hours from commit to production
SELECT d.service,
       percentile_cont(0.5) WITHIN GROUP (
         ORDER BY extract(epoch FROM d.deployed_at - c.committed_at) / 3600
       ) AS median_lead_time_hours
FROM deployments d
JOIN deployment_commits c ON c.deployment_id = d.id
WHERE d.environment = 'production'
GROUP BY d.service;

-- change failure rate
SELECT service,
       avg(CASE WHEN caused_failure THEN 1.0 ELSE 0.0 END) AS change_failure_rate
FROM deployments
WHERE environment = 'production'
GROUP BY service;
  • Use the median, not the mean. One change that sat for three weeks, or one twelve-hour outage, distorts an average and hides the typical experience. Track a high percentile alongside it to see the bad cases.
  • Measure lead time from commit, not from when the ticket was created. The time before coding starts is product and planning work, which is a different and much noisier thing.
  • Be strict and consistent about what counts as a failure: a deployment that led to degraded service for users and required remediation. A failed pipeline run that never reached production is not a change failure; it is the pipeline doing its job.
  • Start with a spreadsheet if necessary. A rough number tracked consistently every month is far more useful than a perfect dashboard that is never built.

Instrumenting the pipeline

The most reliable source for deployment data is the pipeline itself. Emit one event at the end of every production deploy. With Git, you can list exactly which commits are new in this deployment by comparing with the previously deployed commit.

bash
#!/usr/bin/env bash
set -euo pipefail

service="orders"
new_sha="$(git rev-parse HEAD)"
prev_sha="$(cat .last-deployed-sha)"          # recorded by the previous deployment
deployed_at="$(date -u +%Y-%m-%dT%H:%M:%SZ)"

# every commit that is new in this deployment, with its commit timestamp
git log --format='%H %cI' "${prev_sha}..${new_sha}" > commits.txt

jq -n --arg service "$service" --arg sha "$new_sha" --arg at "$deployed_at" \
  --rawfile commits commits.txt \
  '{service: $service, sha: $sha, deployed_at: $at, commits: ($commits | split("\n") | map(select(. != "")))}' \
  > deployment-event.json

curl -fsS -X POST -H 'Content-Type: application/json' \
  --data @deployment-event.json "$METRICS_ENDPOINT"

echo "$new_sha" > .last-deployed-sha

Tag each deployment with the commit SHA, as the artifacts module recommended, and the link from a production incident back to the change that caused it becomes a lookup instead of an investigation. Several open-source projects and most delivery platforms can compute the four keys from your Git host and incident tool directly, which is worth evaluating before you build your own.

Reading the numbers: which constraint is it?

A metric tells you where to look, not what to do. Break lead time into its stages to find where a change spends its life. In most teams the great majority of lead time is waiting, not working.

coding: hoursWAIT: pickupreview, fixesminutesWAIT: daysdeployCommitclock startsPR openedFirst reviewMergedPipeline donebuild + testIn productionclock stopsRelease windowthe usual bottleneck
Where lead time goes: the work is short, and most of the elapsed time is waiting between stages, so the stage with the longest wait is the constraint to fix first.
SymptomLikely constraintWhat helps
Long wait for first reviewLarge PRs, review is nobody's prioritySmaller PRs, a team norm for review time, pairing
Long pipeline stageSlow or serial tests, no cachingCaching, parallel jobs, a faster test pyramid
Merged code waits days to shipManual release process, release windows, change boardAutomated deploys, trunk-based development, feature flags
Low deployment frequencyDeploys are painful or risky, so they are batchedMake deploys boring: automate, canary, fast rollback
High change failure rateLarge changes, weak tests, staging unlike productionSmaller changes, better test coverage, progressive delivery
Long time to restoreSlow detection, no quick rollback, unclear ownershipAlerting on symptoms, one-command rollback, runbooks, on-call

DORA's research also identifies the capabilities that drive the metrics. The technical ones are the contents of this track: version control for everything, trunk-based development, continuous integration, test automation, deployment automation, loosely coupled architecture, and monitoring. The cultural ones matter just as much: a generative, blameless culture, small batch sizes, and limited work in progress. A heavyweight external change-approval board, notably, was found to slow delivery without improving stability.

Tip

Work on one constraint at a time, and re-measure. Improving a stage that is not the bottleneck changes nothing: a build that is five minutes faster is invisible if changes then wait four days for a release window.

Using the metrics without abusing them

Goodhart's law says that when a measure becomes a target, it ceases to be a good measure. Every one of the four keys can be gamed, and will be, if people are rewarded or punished for the number.

  • Deployment frequency rises if you deploy empty changes, or split one release into ten.
  • Change failure rate falls if you stop recording incidents, or redefine "failure".
  • Time to restore falls if incidents are closed before the problem is really fixed.
  • Lead time falls if people commit late, keeping work hidden on their own machines.

The defences are structural. Look at all four together, because gaming one usually damages another: a push for frequency alone shows up as a rising failure rate. Compare a team with its own past, not with other teams, whose systems, constraints and definitions differ. Let teams own their numbers and choose their improvements. And never attach the metrics to individual performance reviews or bonuses.

Keep them in proportion, too. The four keys measure delivery performance: how well you ship. They say nothing about whether you are building the right thing, whether users are happy, or whether the team is burning out. Pair them with product metrics, with the SLOs from the SRE track, and with regular conversations with the people doing the work.

Hands-on practice

Measure your own delivery, then find the bottleneck

  1. Pick one service you work on, or a public open-source project with visible releases. Write down your team's definition of "deployment" and of "change failure" before you look at any data.
  2. From the pipeline history or release tags, count production deployments per week for the last eight weeks.
  3. For the last ten deployments, use git log PREVIOUS..CURRENT --format='%H %cI' to list the commits in each one, and compute the median time from commit to deploy.
  4. From the incident tracker, chat history or postmortems, work out how many of those deployments needed a rollback or hotfix, and how long each restoration took.
  5. For five recent pull requests, record the timestamps of open, first review, approval, merge and deploy. Find the stage with the longest wait.
  6. Propose one change aimed at that stage, predict which metric it should move, and set a date to re-measure.
  7. Add a step to your pipeline that emits a deployment event as JSON with service, SHA and timestamp, even if it only writes to a file for now.
Cheat sheet

Measuring delivery with DORA metrics — at a glance

Main things to focus on

  • Four keys: deployment frequency and lead time measure throughput; change failure rate and time to restore measure stability.
  • Speed and stability improve together. Small, frequent changes are the mechanism.
  • Measure from commit to production, use medians, and keep definitions consistent.
  • Most lead time is waiting. Find the longest wait before optimising anything.
  • A failed pipeline run is not a change failure; a production deployment that needed remediation is.
  • Metrics describe a team and a service. Never use them to rank people or compare unlike teams.
  • Read all four together, since gaming one shows up in another.
  • They measure delivery, not value. Pair them with product metrics and SLOs.

Definitions

Deployment frequencyProduction deployments per unit of time
Lead time for changesMedian time from commit to running in production
Change failure rateDeployments needing remediation divided by all deployments
Time to restore (failed deployment recovery time)Median time from failure to restored service
Throughput = frequency + lead timeHow fast change flows
Stability = failure rate + restore timeHow safely change flows

Formulas

DF = count(prod deploys) / periodReport per service, per week
LT = median(deployed_at - committed_at)Over every commit in each deployment
CFR = failed deploys / total deploysFailed means it needed rollback, hotfix or patch
MTTR = median(restored_at - failure_started_at)Over change-induced failures
batch size ~ commits per deploymentA useful leading indicator; smaller is safer

Getting the data

git log PREV..NEW --format='%H %cI'Commits new in a deployment, with commit time
git describe --tags --abbrev=0Most recent release tag
gh run list --workflow deploy.yml --json conclusion,createdAtDeployment runs from GitHub Actions
gh pr view NUMBER --json createdAt,mergedAt,reviewsTimestamps for the stages of a pull request
percentile_cont(0.5) WITHIN GROUP (ORDER BY x)Median in PostgreSQL
date_trunc('week', ts)Bucket events by week

Symptom to improvement

slow review pickupSmaller PRs; agreed review-time norm
slow pipelineCache, parallelise, trim slow tests
merged but not shippedAutomate deployment; remove release windows; feature flags
high failure rateSmaller changes, better tests, canary releases
slow restoreSymptom-based alerts, one-command rollback, runbooks

Common pitfalls

  • Setting a target for one metric, which people then hit at the expense of the other three.
  • Using the metrics to rank individuals or to compare teams that run very different systems.
  • Averaging lead time, so that a single stale branch hides a healthy typical flow, or the reverse.
  • Counting failed CI runs as change failures, which punishes the pipeline for working.
  • Optimising a stage that is not the bottleneck, such as build speed when changes wait days for approval.
  • Treating good delivery metrics as proof that the product is succeeding.
Quiz

Check your understanding

5 questions · 4 to pass · answers are explained as you go. Your best score is saved on this device only.

Progress and quiz scores are saved in this browser only. Back up or restore on the hub.

Was this lesson useful? Tell me what to improve →