Every engineering leader eventually gets asked some version of "how do we know if the team is actually good?" The honest answer is usually a shrug, a story about a recent incident, or a vague appeal to velocity. That's not a measurement problem you can solve with vibes, and it's not one story points can solve either — story points measure estimation accuracy, not throughput or stability.
DORA metrics — deployment frequency, lead time for changes, change failure rate, and mean time to recovery — are the closest thing the industry has to a research-backed answer. They come out of nearly a decade of research by Nicole Forsgren, Jez Humble, and Gene Kim (published as Accelerate and continued through Google's DevOps Research and Assessment program), correlating specific engineering behaviors with organizational outcomes: profitability, market share, customer satisfaction. The metrics aren't arbitrary. They were chosen because they predict things leadership actually cares about, and because — critically — throughput and stability metrics move together in high-performing orgs rather than trading off against each other.
That last point is the one most teams get backwards. The assumption is that shipping faster means breaking more things. The DORA research says the opposite: elite performers deploy more often and have lower change failure rates and recover faster. Speed and stability aren't in tension when the underlying engineering practices are solid — they're both symptoms of the same underlying health.
What the four DORA metrics actually measure
Deployment frequency — how often you ship to production. Not how often you merge to main, not how often you cut a release branch. How often code reaches users. Elite performers deploy on-demand, multiple times a day. This isn't a vanity metric about being "agile" — it's a proxy for batch size. Small, frequent deployments are inherently lower risk than big, infrequent ones, because there's less surface area to review and less state change to reason about when something goes wrong.
Lead time for changes — the time from code committed to code running in production. This is not the same as cycle time (which some teams measure from ticket creation) and it's not sprint duration. It's a narrower, more useful signal: how long does it take a change that's ready to ship to actually get there? Long lead times usually point to manual approval gates, flaky test suites, or a deployment process nobody trusts enough to automate.
Change failure rate — the percentage of deployments that cause a degradation in production requiring remediation (a rollback, a hotfix, a patch). This is the metric most often gamed, because "failure" is a judgment call unless you define it precisely in advance.
Mean time to recovery (MTTR) — from a research standpoint, DORA has actually moved toward time to restore service language for the same reason MTTR gets criticized elsewhere: a mean is dominated by outliers, and a single four-hour outage can make a team of daily deployers with sub-minute recoveries look bad on paper. Track the distribution, not just the average, if you want the number to mean anything.
Where these numbers actually come from
You cannot get accurate DORA metrics from a survey or from an engineer's gut feeling at the end of the sprint. They have to come from systems of record:
- Deployment frequency and lead time come from your CI/CD pipeline. If you're on GitHub Actions, this means correlating
deploymentevents (or your custom deploy job's completion) against the commit timestamp on the merged PR. GitLab has similar signals via pipeline and environment APIs. - Change failure rate requires linking a deployment to an incident. This only works if incidents are tracked somewhere queryable — PagerDuty, Opsgenie, or even a structured incidents label in your issue tracker — and if someone actually tags which deployment caused it.
- MTTR / time to restore comes from the same incident data: time from detection (not the underlying failure — you often can't know that precisely) to resolution.
A minimal but real instrumentation approach, using GitHub Actions and a lightweight events table:
# .github/workflows/deploy.yml
name: Deploy Production
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Deploy
run: ./scripts/deploy.sh production
- name: Record deployment event
if: success()
run: |
curl -X POST "$METRICS_ENDPOINT/deployments" \
-H "Content-Type: application/json" \
-d '{
"commit_sha": "${{ github.sha }}",
"environment": "production",
"deployed_at": "'"$(date -u +%Y-%m-%dT%H:%M:%SZ)"'",
"committed_at": "'"$(git show -s --format=%cI ${{ github.sha }})"'"
}'
That committed_at vs deployed_at delta, aggregated over a rolling 30-day window, is your lead time. It's not sophisticated — it's a Postgres table with a few columns and a scheduled query computing percentiles. Resist the urge to buy a platform for this before you've proven the team will act on the numbers. Sourcegraph, LinearB, and Faros exist and are fine once you're past a few dozen engineers and want cross-team benchmarking, but a deployments table and a incidents table with a foreign key between them will get you 90% of the value.
Setting up the incident side
Deployment tracking is the easy half. Linking failures back to the deployment that caused them is where teams give up, because it requires discipline at the moment everyone least wants to add process: during an incident.
The minimum viable version is a required field on your incident postmortem template: "deployment(s) implicated" with commit SHAs. If you use PagerDuty, a custom field on the incident works. If you use Jira Service Management, same idea. The point isn't the tool — it's making the linkage mandatory rather than something someone reconstructs from memory three weeks later when a dashboard looks wrong.
Define "change failure" precisely before you start measuring, and write it down somewhere everyone can see:
- A deployment that required a rollback within 24 hours
- A deployment that required a hotfix deployed within 24 hours
- A deployment directly named as the cause in an incident postmortem
Anything vaguer than that becomes a debate every time the number looks bad.
The pitfalls that make these metrics actively harmful
Optimizing the metric instead of the system. The fastest way to improve deployment frequency on paper is to deploy no-op changes or split real changes into artificially small commits that don't represent complete units of work. If engineers know these numbers show up in a performance review, they will find the path of least resistance to a good number, and it usually isn't the path that makes the system better. DORA metrics are team and org-level health signals, not individual performance metrics. The moment you put a single engineer's name next to a lead-time number, you've broken the metric.
Comparing teams without normalizing context. A team shipping a stateless frontend and a team shipping a database migration engine will never have comparable change failure rates, and that's fine. Use each team's own metrics as a trend line against its own history, not as a leaderboard against other teams with fundamentally different risk profiles.
Chasing elite-tier benchmarks blindly. The "elite/high/medium/low" tiers from the State of DevOps reports are useful as a rough compass, not a target to hit regardless of context. A team shipping firmware to medical devices should not have the same deployment frequency ambitions as a team shipping a marketing site, and forcing that comparison creates pressure to cut corners on validation that exists for good reasons.
Measuring only what's easy. Deployment frequency is trivial to instrument from CI logs. Change failure rate requires organizational buy-in to link incidents to deployments. Teams often report deployment frequency proudly while quietly not measuring change failure rate at all — which produces a metrics program that only ever tells a flattering story.
Ignoring the denominator. A change failure rate of 5% means something completely different at 2 deployments a week versus 50 deployments a day. Report the underlying counts next to the percentage, not just the percentage.
Making the numbers useful instead of decorative
The teams that get real value out of DORA metrics review them the same way they review any other operational signal: in retros, as trend lines, with someone empowered to ask "why did lead time creep up this month" and follow the answer to a root cause — usually a slow test suite, a manual approval step nobody trusts to remove, or a deploy process that only one person understands. If the metrics live in a quarterly slide deck and nowhere else, they aren't measuring engineering performance. They're measuring how good your slide deck looks.
Start smaller than you think you need to. Instrument deployment frequency and lead time first — they're purely mechanical and require no behavioral change to collect accurately. Add change failure rate and time-to-restore once you've built the incident-linking habit. Trying to stand up all four at once, with dashboards and alerting thresholds before anyone trusts the underlying data, is how these programs die in month two.
If you're trying to get real visibility into how your engineering org actually performs — not a vanity dashboard, but numbers your team can act on — get in touch. We've built this instrumentation from scratch on GitHub Actions, GitLab CI, and Jenkins pipelines, and we can help you avoid the version of this that becomes Goodhart's Law made manifest.
Further Reading
- Accelerate: State of DevOps Reports — the official DORA research site with the latest annual State of DevOps report and the full metrics definitions
- Google Cloud's DORA metrics guide — a practical walkthrough of the "Four Keys" project for computing these metrics from CI/CD data
Working on something similar?
We help engineering teams implement the practices covered in this post. First call is free.
Start a conversation →