Devops Metrics Dora

Production engineering guide for devops metrics dora covering patterns, implementation strategies, and operational best practices.

DevOps Metrics DORA provides a shared language for evaluating software delivery performance across engineering teams. It matters when teams need to benchmark their velocity, reliability, and stability—especially during scaling, post-incident reviews, or when aligning multiple teams around a common definition of “done.” The four core metrics—Lead Time for Changes, Deployment Frequency, Change Failure Rate, and Mean Time to Recovery—are grounded in real-world data from high-performing teams and apply to any software delivery pipeline.

Measuring Delivery Performance

To evaluate how well a team delivers software, track four metrics derived from the lifecycle of a code change: from commit to production. These metrics are not derived from surveys or opinions but from event logs and deployment records.

Lead Time for Changes

Lead Time for Changes is the duration from code commit to production deployment. It measures how quickly a team can turn an idea into a live feature.

A commit to main triggers a CI pipeline. Each pipeline run must emit a deployment event with:

Example log entry from a CI system:

{
  "event": "deployment",
  "commit_hash": "a1b2c3d4e5f6",
  "timestamp": "2024-04-12T10:30:15Z",
  "environment": "production",
  "status": "success",
  "pipeline_id": "ci-789"
}

The lead time is computed as:

SELECT
  commit_hash,
  MIN(timestamp) AS first_deployment_timestamp,
  MAX(timestamp) AS last_deployment_timestamp,
  (MAX(timestamp) - MIN(timestamp)) AS lead_time
FROM deployments
WHERE environment = 'production'
GROUP BY commit_hash

Common failure mode: A deployment is recorded but the commit_hash is missing or incorrect. If the CI system pushes to main but the deployment event references develop, lead time is underestimated by days.

Deployment Frequency

Deployment Frequency measures how often changes are deployed to production.

A deployment event must include environment = 'production' and timestamp.

To calculate weekly deployment frequency:

SELECT
  DATE_TRUNC('week', timestamp) AS week,
  COUNT(*) AS deployments
FROM deployments
WHERE environment = 'production'
  AND timestamp >= '2024-04-01'
GROUP BY week
ORDER BY week;

Sharp edge: A deployment is a single event, but teams often batch multiple changes into one deployment. This leads to a mismatch between “number of deployments” and “number of changes.” A team with 100 deployments per week may only have 20 merged PRs.

To reconcile, enrich deployment events with a change_ids array:

{
  "event": "deployment",
  "commit_hash": "a1b2c3d4e5f6",
  "timestamp": "2024-04-12T10:30:15Z",
  "environment": "production",
  "status": "success",
  "change_ids": [
    "PR-45",
    "PR-46",
    "PR-47"
  ]
}

Now, lead time can be computed per change ID, not just per commit.

Change Failure Rate

Change Failure Rate is the percentage of deployments that result in a failure within a defined window.

A health check service polls the deployed application every 5 minutes. It records:

A failure is detected when:

The failure detection system logs:

{
  "event": "health_check",
  "service_id": "user-api",
  "timestamp": "2024-04-12T10:35:10Z",
  "error_rate": 0.072,
  "response_time_ms": 643,
  "status_code": 500
}

A deployment is considered failed if any health check in the first hour after deployment shows failure.

Common mistake: Assuming all deployments are successful unless explicitly marked. A deployment event with status = 'success' does not imply that the system is stable. A service may deploy successfully but fail to serve requests, causing a silent failure.

Mean Time to Recovery (MTTR)

MTTR measures how quickly a team restores service after a failure.

An incident is recorded when:

Each incident must include:

MTTR is computed as:

SELECT
  AVG(recovered_at - detected_at) AS mttr_seconds
FROM incidents
WHERE service_id = 'user-api';

Failure mode: A team logs a deployment but forgets to link it to an incident. If a deployment causes an incident but no deployment_id is present, MTTR is underestimated because the recovery time is measured from the incident’s detected_at, but the root cause is not tied to a deployment.

Integrating the Four Metrics

To build a DORA dashboard, collect events from multiple systems using a common schema.

Unified Event Schema

All systems emit events in a standard format:

{
  "event_type": "deployment|health_check|incident|change",
  "timestamp": "2024-04-12T10:30:15Z",
  "payload": {
    "commit_hash": "a1b2c3d4e5f6",
    "environment": "production",
    "status": "success",
    "service_id": "user-api",
    "error_rate": 0.03,
    "deployment_id": "ci-789",
    "incident_id": "inc-1023"
  }
}

Events are pushed to a central log storage (e.g., PostgreSQL, Kafka, or a time-series database) via:

Pipeline-Driven Metric Collection

A CI/CD pipeline captures all DORA metrics:


name: Deploy to Production
on:
  push:
    branches:
      - main

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Build
        run: |
          npm run build
      - name: Test
        run: |
          npm test
      - name: Deploy
        run: |
          ./deploy.sh --to=production --commit=${{ github.sha }}
        # deploy.sh emits deployment event
        # and updates status in GitHub
      - name: Record Deployment Event
        run: |
          curl -X POST https://events.example.com/v1/events -d @- <<EOF
{
  "event_type": "deployment",
  "timestamp": "$(date -u +'%Y-%m-%dT%H:%M:%SZ')",
  "payload": {
    "commit_hash": "${{ github.sha }}",
    "environment": "production",
    "status": "success",
    "service_id": "user-api",
    "deployment_id": "ci-${{ github.run_id }}"
  }
}
EOF

The deploy.sh script uses curl to emit events:

#!/bin/bash
set -euo pipefail

DEPLOY_TO="$1"
COMMIT_HASH="$2"
DEPLOY_ID="$3"

# Deploy to target
echo "Deploying ${COMMIT_HASH} to ${DEPLOY_TO}"
# ... deployment logic ...

# Emit event
curl -X POST https://events.example.com/v1/events -d @- <<EOF
{
  "event_type": "deployment",
  "timestamp": "$(date -u +'%Y-%m-%dT%H:%M:%SZ')",
  "payload": {
    "commit_hash": "${COMMIT_HASH}",
    "environment": "${DEPLOY_TO}",
    "status": "success",
    "deployment_id": "${DEPLOY_ID}"
  }
}
EOF

Common Pitfalls and Silent Failures

Confusing Deployment Frequency with Release Frequency

Teams often conflate deployment frequency (number of deployments) with release frequency (number of releases). A release may include many deployments. The key is to track each deployment independently.

Example: A team releases a new version every two weeks but deploys daily. The DORA dashboard shows:

But if the release version is not tied to deployment events, lead time per release is off.

Underreporting Change Failure Rate

A deployment is marked as successful in CI, but the application is not healthy. The team fails to detect this until the next day.

Solution: Add automated health checks that run in parallel with deployment. A health check service listens for deployment events and starts monitoring the service.

MTTR Overestimation due to Delayed Incident Resolution

An incident is detected at 10:00 but resolved at 14:00, yet the recovery event is logged at 15:00. This inflates MTTR.

Best practice: Use detected_at and recovered_at with precision. The system should:

An incident is created for a deployment failure but lacks deployment_id. The MTTR calculation uses only the incident’s detected_at and recovered_at, ignoring when the deployment occurred.

Fix: The incident creation system must:

Using DORA for Continuous Improvement

DORA metrics are not just reports—they drive team decisions.

Each metric becomes a target for improvement, and the team’s shared understanding of delivery performance grows.

Summary

DORA metrics are not a dashboard but a shared language for delivery excellence. They require:

When implemented well, DORA enables teams to measure what matters, identify bottlenecks, and continuously improve their delivery performance.

This page was rewritten on 15 October 2026. It replaced a templated version that was not specific to its own title. How these pages are written and checked. If anything here is wrong, tell us at [email protected] and we will correct it.