DORA Metrics: Deployment Frequency, Lead Time, MTTR, and Change Failure Rate
Measure and improve software delivery with DORA metrics in 2026 — deployment frequency, lead time for changes, mean time to restore, change failure rate, how to
DORA Metrics: Deployment Frequency, Lead Time, MTTR, and Change Failure Rate
The DORA (DevOps Research and Assessment) metrics are the four measurements that most reliably predict both software delivery performance and organizational outcomes. Teams with high DORA metrics ship faster, have fewer incidents, and recover from them more quickly.
The point is not to game the numbers — it's to use them to diagnose where your delivery pipeline is hurting and fix the underlying bottlenecks.
The Four Metrics
| Metric | What It Measures | Elite | High | Medium | Low |
|---|---|---|---|---|---|
| Deployment Frequency | How often you deploy to production | On-demand (multiple/day) | Daily–weekly | Weekly–monthly | Monthly or less |
| Lead Time for Changes | Commit → production time | < 1 hour | 1 day – 1 week | 1–6 months | > 6 months |
| Change Failure Rate | % of deployments causing an incident | 0–5% | 5–10% | 11–15% | > 15% |
| MTTR (Time to Restore) | Time to recover from an incident | < 1 hour | < 1 day | 1 day – 1 week | > 1 week |
Elite vs Low performer reality:
- Elite teams deploy 973× more frequently than low performers
- Elite teams have 6,570× faster lead time
- MTTR is 6,570× faster for elite vs low performers
- Elite teams have a 7× lower change failure rate
Collecting Each Metric
1. Deployment Frequency
// scripts/metrics/deployment-frequency.ts
// Pull deployment data from GitHub Deployments API
import { Octokit } from '@octokit/rest';
const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });
async function getDeploymentFrequency(
owner: string,
repo: string,
daysBack: number = 30,
): Promise<{ deploymentsPerDay: number; totalDeploys: number }> {
const since = new Date(Date.now() - daysBack * 24 * 60 * 60 * 1000).toISOString();
const deployments = await octokit.paginate(octokit.repos.listDeployments, {
owner, repo,
environment: 'production',
per_page: 100,
});
const recentDeploys = deployments.filter(d =>
new Date(d.created_at) > new Date(since)
);
return {
deploymentsPerDay: recentDeploys.length / daysBack,
totalDeploys: recentDeploys.length,
};
}
// Example output:
// { deploymentsPerDay: 3.2, totalDeploys: 96 } → Elite tier
2. Lead Time for Changes
// Lead time = time from first commit in PR → deployment to production
async function getLeadTime(
owner: string,
repo: string,
): Promise<{ p50LeadTimeHours: number; p95LeadTimeHours: number }> {
const deployments = await octokit.paginate(octokit.repos.listDeployments, {
owner, repo, environment: 'production', per_page: 50,
});
const leadTimes: number[] = [];
for (const deploy of deployments.slice(0, 20)) { // Last 20 deployments
// Get the commit SHA for this deployment
const commitSha = deploy.sha;
const deployedAt = new Date(deploy.created_at);
// Find the PR that introduced this commit
const prs = await octokit.repos.listPullRequestsAssociatedWithCommit({
owner, repo, commit_sha: commitSha,
});
if (prs.data.length > 0) {
const pr = prs.data[0];
// Lead time: PR first commit → deployment
const firstCommitAt = new Date(pr.created_at);
const leadTimeHours = (deployedAt.getTime() - firstCommitAt.getTime()) / (1000 * 60 * 60);
leadTimes.push(leadTimeHours);
}
}
leadTimes.sort((a, b) => a - b);
const p50 = leadTimes[Math.floor(leadTimes.length * 0.5)];
const p95 = leadTimes[Math.floor(leadTimes.length * 0.95)];
return { p50LeadTimeHours: p50, p95LeadTimeHours: p95 };
}
3. Change Failure Rate
// Change Failure Rate = incidents caused by deployments / total deployments
// Requires: linking PagerDuty incidents to deployments
import PagerDuty from 'node-pagerduty';
async function getChangeFailureRate(daysBack: number = 30): Promise<number> {
const since = new Date(Date.now() - daysBack * 24 * 60 * 60 * 1000);
// Total deployments
const deploys = await getDeploymentCount('production', since);
// Incidents caused by deployments (tagged with "deployment" or "regression")
const pd = new PagerDuty(process.env.PAGERDUTY_API_KEY!);
const incidents = await pd.incidents.listIncidents({
since: since.toISOString(),
urgencies: ['high', 'low'],
});
const deploymentCaused = incidents.incidents.filter((inc: any) =>
inc.description?.toLowerCase().includes('deploy') ||
inc.title?.toLowerCase().includes('regression') ||
inc.tags?.includes('deployment-caused')
);
return deploys > 0 ? deploymentCaused.length / deploys : 0;
}
4. MTTR (Mean Time to Restore)
// MTTR = average time from incident detection to resolution
async function getMTTR(daysBack: number = 30): Promise<number> {
const since = new Date(Date.now() - daysBack * 24 * 60 * 60 * 1000);
const pd = new PagerDuty(process.env.PAGERDUTY_API_KEY!);
const incidents = await pd.incidents.listIncidents({
since: since.toISOString(),
statuses: ['resolved'],
});
const resolveTimes = incidents.incidents
.filter((inc: any) => inc.resolved_at)
.map((inc: any) => {
const detected = new Date(inc.created_at).getTime();
const resolved = new Date(inc.resolved_at).getTime();
return (resolved - detected) / (1000 * 60); // Minutes
});
if (resolveTimes.length === 0) return 0;
return resolveTimes.reduce((a, b) => a + b, 0) / resolveTimes.length;
}
🌐 Looking for a Dev Team That Actually Delivers?
Most agencies sell you a project manager and assign juniors. Viprasol is different — senior engineers only, direct Slack access, and a 5.0★ Upwork record across 100+ projects.
- React, Next.js, Node.js, TypeScript — production-grade stack
- Fixed-price contracts — no surprise invoices
- Full source code ownership from day one
- 90-day post-launch support included
Building a DORA Dashboard
// scripts/metrics/dora-report.ts
async function generateDoraReport(): Promise<void> {
const [deployFreq, leadTime, cfr, mttr] = await Promise.all([
getDeploymentFrequency('yourorg', 'your-repo', 30),
getLeadTime('yourorg', 'your-repo'),
getChangeFailureRate(30),
getMTTR(30),
]);
const report = {
period: 'Last 30 days',
deploymentFrequency: {
value: deployFreq.deploymentsPerDay.toFixed(1),
unit: 'deployments/day',
tier: classifyDeployFreq(deployFreq.deploymentsPerDay),
},
leadTime: {
p50: `${leadTime.p50LeadTimeHours.toFixed(1)} hours`,
p95: `${leadTime.p95LeadTimeHours.toFixed(1)} hours`,
tier: classifyLeadTime(leadTime.p50LeadTimeHours),
},
changeFailureRate: {
value: `${(cfr * 100).toFixed(1)}%`,
tier: classifyCFR(cfr),
},
mttr: {
value: `${mttr.toFixed(0)} minutes`,
tier: classifyMTTR(mttr),
},
};
console.table(report);
// Also write to metrics store (Datadog, Prometheus, etc.)
await sendToDatadog(report);
}
function classifyDeployFreq(perDay: number): 'elite' | 'high' | 'medium' | 'low' {
if (perDay >= 1) return 'elite';
if (perDay >= 1/7) return 'high'; // At least weekly
if (perDay >= 1/30) return 'medium'; // At least monthly
return 'low';
}
What to Fix First
The bottleneck analysis depends on which metrics are weakest:
🚀 Senior Engineers. No Junior Handoffs. Ever.
You get the senior developer, not a project manager who relays your requirements to someone you never meet. Every Viprasol project has a senior lead from kickoff to launch.
- MVPs in 4–8 weeks, full platforms in 3–5 months
- Lighthouse 90+ performance scores standard
- Works across US, UK, AU timezones
- Free 30-min architecture review, no commitment
DORA Improvement Priorities
Low Deployment Frequency
Root causes:
- Long QA/approval gates before deployment
- Fear of deployments (related to high CFR)
- Manual deployment process Fixes:
- Automate deployment pipeline end-to-end
- Implement feature flags (decouple deploy from release)
- Deploy smaller changesets more often
Long Lead Time
Root causes:
- Large batches (PRs with 1000+ lines)
- Long-running CI (> 20 min)
- Code review bottleneck (1–2 reviewers for all PRs) Fixes:
- Break PRs into smaller units (< 400 lines)
- Parallelize and cache CI jobs
- Add more reviewers; remove bottleneck approver
High Change Failure Rate
Root causes:
- Insufficient test coverage on critical paths
- No staging environment that mirrors production
- Schema migrations without backward compatibility Fixes:
- Add E2E tests for top 5 user flows
- Implement expand-contract migrations
- Add canary deployments (route 5% of traffic to new version first)
High MTTR
Root causes:
- No runbooks for common failures
- On-call engineers unfamiliar with the system
- Slow root cause identification (missing observability) Fixes:
- Write runbooks for top 10 alert types
- Improve distributed tracing and logging
- Practice incident response (game days)
---
## The Fifth DORA Metric: Reliability (2023+)
The 2023 DORA report added a fifth metric: **Reliability** — measuring whether you're meeting your reliability targets (SLOs). Teams can be fast without being reliable; this metric ensures both.
```typescript
// Reliability: % of SLO windows met in the last 30 days
async function getReliabilityScore(): Promise<number> {
const sloWindows = await fetchSLOWindowResults(30); // From Datadog/Prometheus
const windowsMet = sloWindows.filter(w => w.errorBudgetRemaining > 0).length;
return windowsMet / sloWindows.length;
}
// Target: > 95% of SLO windows met
Working With Viprasol
We help engineering teams instrument and improve their DORA metrics — CI/CD pipeline optimization, deployment automation, observability setup for MTTR reduction, and the process changes (PR sizing, review culture, incident management) that move teams from low to elite tier.
→ Talk to our team about engineering performance and delivery optimization.
See Also
- CI/CD Pipeline Setup — the foundation for deployment frequency
- Incident Management — MTTR improvement through process
- Feature Flags Advanced — decoupling deploy from release
- Observability and Monitoring — instrumentation for MTTR
- Web Development Services — engineering advisory and process improvement
About the Author
Viprasol Tech Team
Custom Software Development Specialists
The Viprasol Tech team specialises in algorithmic trading software, AI agent systems, and SaaS development. With 100+ projects delivered across MT4/MT5 EAs, fintech platforms, and production AI systems, the team brings deep technical experience to every engagement. Based in India, serving clients globally.
Need a Modern Web Application?
From landing pages to complex SaaS platforms — we build it all with Next.js and React.
Free consultation • No commitment • Response within 24 hours
Need a custom web application built?
We build React and Next.js web applications with Lighthouse ≥90 scores, mobile-first design, and full source code ownership. Senior engineers only — from architecture through deployment.