Laptop to Production

Measuring delivery

The four DORA numbers every team is judged on.

Time
30 minutes
Level
Beginner

Part 1: The problem

QuickCart, the planning meeting

QuickCart has started releasing every week instead of every month. At the planning meeting, the founder asks a simple question: “Are we getting better?”

Leo says yes: they ship four times as often. Noor says no: last Tuesday’s release broke checkout. Theo says the on-call nights feel worse. Everyone is describing something real, and nobody can answer the question.

QuickCart doesn’t need opinions. It needs those four numbers.

Part 2: The idea

The DORA metrics are four numbers that together describe how well a team delivers software. Two measure speed. Two measure stability.

MetricThe question it answersHow to measure itMeasures
Deployment frequencyHow often do we put changes in production?Count deployments to production in a periodSpeed
Lead time for changesHow long does a change take from commit to production?For each change: time deployed minus time of its first commitSpeed
Change failure rateWhat share of our deployments hurt users?Deployments that needed a fix, rollback or hotfix, divided by all deploymentsStability
Time to restoreWhen a deployment hurts users, how long until it’s fixed?For each failure: time fixed minus time it startedStability

Why all four, and never just one

Any one number on its own can be made to look good in a harmful way:

If you only watchYou can “improve” it byWhich hurts
Deployment frequencyDeploying the same big batch more often, or skipping testsChange failure rate
Change failure rateDeploying rarely and testing for weeksDeployment frequency and lead time
Lead timeRushing changes throughChange failure rate
Time to restoreMarking incidents fixed before they really areUsers, who are still affected

Watched together, the only reliable way to improve all four is the one the previous lesson showed: smaller batches, with automated testing and deployment. A small change is quick to ship, rarely breaks things, and is easy to undo when it does.

Key point: Measure speed and stability together. Good teams improve both at once, by making each change smaller.

What good looks like

Past DORA reports sorted teams into groups. The boundaries change from year to year, so treat these as rough:

MetricThe strongest teamsThe weakest teams
Deployment frequencySeveral times a dayLess than once a month
Lead time for changesUnder a dayMore than a month
Change failure rateAround 5 to 15%Around half of deployments
Time to restoreUnder an hourMore than a week

The point isn’t to hit a group’s numbers. It’s to know where you are, and to see whether a change you make, like adding automated tests, moves all four the right way.

Two rules for using them

  • They describe a team’s system, not a person. Rank people by them and people will game them: split one change into ten tiny deploys, and frequency looks wonderful while nothing gets better.
  • Measure from what your tools already record. Your git history, your deploy logs and your incident records hold most of it. The lab shows how far plain git gets you.

Part 3: See it

Change how many changes go out in each release, and watch all four numbers. The squares are the changes in one release; red ones are bad changes hiding among the rest.

Changes per release
Deployment frequencyspeed
How often you release
About 4 a day
Lead time for changesspeed
Commit to running in production
Hours
Change failure ratestability
Releases that cause a problem
3%
Time to restorestability
From problem to fixed
Under an hour

A longer bar is better. A simple model, not real data: about 4 changes finished a day, each with a 3% chance of causing a problem.

1 change per releaseEvery change ships on its own. If one is bad, it's the only suspect, and undoing it is easy. Fast and stable.

What to notice: all four numbers get worse together as the batch grows. There’s no setting where you trade a little speed for a lot of stability. Big batches make you slower and more fragile.

Part 4: Do it

Free — you only read your own project’s history.

You’ll measure deployment frequency, lead time, change failure rate and time to restore for a real project, using only git. About 20 minutes.

You need a git project that deploys from its main branch, where each merge to main goes to production. Most web and backend projects work like this. If your project’s main branch is called something else, such as master, use that name wherever you see main. Open the terminal in the project’s folder.

The example output below comes from QuickCart’s order service. Yours will show your own history.

  1. List what reached main in the last 30 days

    Terminal
    git log --first-parent --since="30 days ago" --format="%h  %ad  %s" --date=iso main
    PartWhat it means
    git loglist commits, newest first
    --first-parentonly the commits made on main, such as merges, not every commit inside each branch that was merged
    --since="30 days ago"only the last 30 days
    --format="%h %ad %s"each line shows the short ID, the date and the message
    --date=isodates with the time of day, like 2026-09-16 10:45:00 +0000
    mainthe branch to read
    You should see
    c14440c  2026-09-22 15:30:00 +0000  Merge pull request #45 from eta
    dc69072  2026-09-16 10:45:00 +0000  Merge pull request #44 from promo2
    9c91e1d  2026-09-09 18:02:00 +0000  Merge pull request #43 from fix-total
    6bb6f9d  2026-09-09 16:20:00 +0000  Merge pull request #42 from promo
    15374d9  2026-09-03 11:05:00 +0000  Merge pull request #41 from menu-photos

    Each line is one change reaching main, so, in a project that deploys every merge, one deployment. Keep this list open; the later steps use its times.

  2. Count them: deployment frequency

    Terminal
    git rev-list --count --first-parent --since="30 days ago" main
    PartWhat it means
    git rev-listlist commit IDs, with no other detail
    --countprint only how many there are
    --first-parent --since="30 days ago"the same commits as the last step
    mainthe branch to count
    You should see
    5

    QuickCart deployed 5 times in 30 days: a little more than once a week. That’s its deployment frequency.

  3. Measure one change: lead time

    Pick a merge from your list. Put its ID in place of the highlighted one in both places, and list the commits it brought in:

    Terminal
    git log --reverse --format="%h  %ad  %s" --date=iso "dc69072^1..dc69072^2"
    PartWhat it means
    git log --reverselist commits, oldest first
    --format="%h %ad %s" --date=isoID, date with time, and message
    dc69072^1the merge’s first parent: what main looked like just before the merge
    dc69072^2its second parent: the tip of the branch that was merged in
    A..Bcommits reachable from B but not from A. Here: exactly the commits the branch added
    the quotesstop the terminal treating ^ as a special character
    You should see
    e1159a2  2026-09-14 09:00:00 +0000  Promo codes at checkout, with tests for totals
    dea5847  2026-09-15 14:10:00 +0000  Handle expired codes

    The first commit was on 14 September at 09:00. From step 1, the merge was on 16 September at 10:45. So this change’s lead time was about 2 days and 2 hours, plus however long your deploy takes after a merge. Do the same for three or four merges and take the typical value.

  4. Find the failures: change failure rate

    Look for changes that undid or patched an earlier one:

    Terminal
    git log --since="30 days ago" --format="%h  %ad  %s" --date=iso -i --grep="revert" --grep="hotfix" main
    PartWhat it means
    git log --since="30 days ago"commits from the last 30 days. No --first-parent this time, so commits inside merged branches are included
    --format="%h %ad %s" --date=isoID, date with time, and message
    -iignore upper and lower case
    --grep="revert" --grep="hotfix"messages containing either word
    mainthe branch to read
    You should see
    a8bbe85  2026-09-09 17:05:00 +0000  Revert promo codes: totals wrong for some orders

    One of QuickCart’s 5 deployments, the promo codes in #42, had to be undone. Its change failure rate is 1 ÷ 5 = 20%.

    Git only knows about failures someone fixed with a commit. If your team keeps incident records, count from those instead; they’re more complete.

  5. Time the recovery: time to restore

    For each failure, find when the bad change went out and when the fix went out, both in the step 1 list:

    EventFrom the listTime
    The bad change is deployed6bb6f9d Merge pull request #42 from promo16:20
    The fix is deployed9c91e1d Merge pull request #43 from fix-total18:02

    QuickCart’s time to restore was 1 hour 42 minutes. Strictly, the clock starts when users were first affected, which your monitoring knows better than git. The deploy time is a good first estimate.

  6. Write down your four numbers

    MetricQuickCartYours
    Deployment frequency5 in 30 days
    Lead time for changesAbout 2 days
    Change failure rate20%
    Time to restoreAbout 2 hours
    You should see

    Four numbers for your project. Look at the one that’s furthest from the strongest teams in the idea. Measure again in a month to see if it moved.

  7. Clean-up step: Clean up

    Nothing to delete. Every command here only reads git history.

Part 5: Check yourself

Which two DORA metrics measure speed?

A team starts deploying ten times more often, and their change failure rate goes up. What should they conclude?

What does lead time for changes measure?

QuickCart made 20 deployments last month. 3 of them caused problems that needed a fix. What is the change failure rate?

A manager wants to rank every developer by their personal deployment frequency. What's the problem?

Part 6: Cheat sheet

On one card
Metric or commandIn one line
Deployment frequencyHow often you deploy to production. Speed
Lead time for changesCommit to running in production. Speed
Change failure rateShare of deployments that needed a fix. Stability
Time to restoreFrom a failure starting to it being fixed. Stability
The ruleWatch all four together. Smaller batches improve all of them
NeverUse them to rank individual people
git rev-list --count --first-parent --since="30 days ago" mainHow many changes reached main
git log --reverse "ID^1..ID^2"The commits a merge brought in, oldest first
git log -i --grep="revert"Changes that undid earlier ones

Finished the build and the quiz? Mark it done to fill in its stop on the route map.