npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@baphy/dora

v1.1.0

Published

DORA metrics calculator — Deployment Frequency, Lead Time, Change Failure Rate, MTTR

Readme

@baphy/dora

Calculate the four DORA engineering performance metrics from any data source

npm version npm downloads bundle size CI license TypeScript


Overview

@baphy/dora calculates the four DORA engineering performance metrics:

| Metric | Measures | |---|---| | Deployment Frequency | How often you deploy to production | | Lead Time for Changes | Time from first commit to production | | Change Failure Rate | Percentage of deployments that cause incidents | | MTTR | Time to restore service after an incident |

Each metric returns a level (elite · high · medium · low) based on the Google DORA 2023 thresholds, which are fully overridable.

Platform-agnostic — the library defines normalized input types. Map your own data (GitHub, GitLab, Bitbucket, Jira, or anything else) to those types before calling the functions. No adapters, no platform lock-in.

Zero dependencies · Synchronous · O(n) · Configurable labels and thresholds

Installation

npm install @baphy/dora

Usage

All four metrics at once

import { calcDora } from '@baphy/dora'
import type { DeploymentEvent, ChangeEvent, IncidentEvent } from '@baphy/dora'

const result = calcDora({
  deployments,  // DeploymentEvent[]
  changes,      // ChangeEvent[]
  incidents,    // IncidentEvent[]
  period: { start, end },
})

console.log(result)
// {
//   deploymentFrequency: { value: 1.4, level: 'elite', label: '1.4 deploys/day' },
//   leadTime:            { value: 3,   level: 'high',  label: '3 hours' },
//   changeFailureRate:   { value: 8.9, level: 'high',  label: '8.9%' },
//   mttr:                { value: 0.5, level: 'elite', label: '30 minutes' },
//   overall: 'high',
// }

Only provide the data you have — any omitted input means that metric is absent from the result:

// only deployments → only deploymentFrequency + changeFailureRate are computed
calcDora({ deployments })

Individual metric functions

import { calcDeploymentFrequency, calcLeadTime, calcChangeFailureRate, calcMttr } from '@baphy/dora'

const df  = calcDeploymentFrequency(deployments, period)
const lt  = calcLeadTime(changes)
const cfr = calcChangeFailureRate(deployments)
const mtr = calcMttr(incidents)

Input Types

Map your data to these normalized types before calling any function:

interface DeploymentEvent {
  deployedAt: Date
  success: boolean   // false if the deploy triggered an incident / was rolled back
}

interface ChangeEvent {
  startedAt: Date    // first commit, PR open, ticket created — whatever fits your workflow
  deployedAt: Date   // when it reached production
}

interface IncidentEvent {
  failedAt: Date
  restoredAt: Date
}

interface Period {
  start: Date
  end: Date
}

Mapping from GitHub data

import { calcDora } from '@baphy/dora'
import type { DeploymentEvent } from '@baphy/dora'

// GitHub Deployments API → DeploymentEvent[]
const deployments: DeploymentEvent[] = githubDeployments.map((d) => ({
  deployedAt: new Date(d.created_at),
  success: d.statuses.some((s) => s.state === 'success'),
}))

calcDora({ deployments, period: { start, end } })

API

calcDora(input)

function calcDora(input: CalcDoraInput): DoraResult

interface CalcDoraInput {
  deployments?: DeploymentEvent[]
  changes?: ChangeEvent[]
  incidents?: IncidentEvent[]
  period?: Period                     // defaults to last 90 days
  thresholds?: Partial<DoraThresholds>
  labels?: CalcDoraLabels             // per-metric label formatter overrides
}

interface DoraResult {
  deploymentFrequency?: DoraLevelResult
  leadTime?: DoraLevelResult
  changeFailureRate?: DoraLevelResult
  mttr?: DoraLevelResult
  overall?: DoraLevel                 // worst level among computed metrics
}

Individual metric functions

function calcDeploymentFrequency(
  events: DeploymentEvent[],
  period: Period,
  options?: { thresholds?: Partial<DeploymentFrequencyThresholds>; label?: LabelFormatter }
): DoraLevelResult

function calcLeadTime(
  changes: ChangeEvent[],
  options?: { thresholds?: Partial<LeadTimeThresholds>; label?: LabelFormatter }
): DoraLevelResult

function calcChangeFailureRate(
  events: DeploymentEvent[],
  options?: { thresholds?: Partial<ChangeFailureRateThresholds>; label?: LabelFormatter }
): DoraLevelResult

function calcMttr(
  incidents: IncidentEvent[],
  options?: { thresholds?: Partial<MttrThresholds>; label?: LabelFormatter }
): DoraLevelResult

Return type

type DoraLevel = 'elite' | 'high' | 'medium' | 'low'

interface DoraLevelResult {
  value: number    // raw computed value (deploys/day, hours, or percentage)
  level: DoraLevel
  label: string    // human-readable string produced by the formatter
}

Empty-input contract — all functions return { value: 0, level: 'low', label: '—' } when given an empty array. They never throw.

Thresholds

Default thresholds follow the Google DORA 2023 Research Program:

| Metric | Elite | High | Medium | Low | |---|---|---|---|---| | Deployment Frequency | ≥ 1/day | ≥ 1/week | ≥ 1/month | < 1/month | | Lead Time for Changes | ≤ 1 hour | ≤ 1 week | ≤ 1 month | > 1 month | | Change Failure Rate | ≤ 5% | ≤ 10% | ≤ 15% | > 15% | | MTTR | ≤ 1 hour | ≤ 24 hours | ≤ 1 week | > 1 week |

Override any threshold globally via calcDora({ thresholds }) or per-call via each function's options.thresholds:

import { mergeThresholds, DEFAULT_THRESHOLDS } from '@baphy/dora'

// partial override — unspecified fields keep the defaults
const thresholds = mergeThresholds({
  deploymentFrequency: { elite: 2, high: 0.5, medium: 0.1 },
})

calcDora({ deployments, thresholds })

Configurable Labels

Each metric has a built-in English label formatter. Provide your own LabelFormatter to customise the output — including locale, units, or appending extra context:

type LabelFormatter = (value: number, level: DoraLevel) => string

Consumer with Spanish locale:

import { calcDeploymentFrequency } from '@baphy/dora'

const n = new Intl.NumberFormat('es-MX', { maximumFractionDigits: 1 })

calcDeploymentFrequency(events, period, {
  label: (v) => v >= 1
    ? `${n.format(v)} despliegues/día`
    : `${n.format(v * 7)} despliegues/semana`,
})
// → "1,4 despliegues/día"

Extending the built-in formatter:

import { calcDeploymentFrequency, labelDeploymentFrequency } from '@baphy/dora'

calcDeploymentFrequency(events, period, {
  label: (v, l) => `${labelDeploymentFrequency(v, l)} · ${l.toUpperCase()}`,
})
// → "1.4 deploys/day · ELITE"

Per-metric overrides via calcDora:

calcDora({
  deployments,
  labels: {
    deploymentFrequency: (v) => `${v.toFixed(2)} dep/day`,
    changeFailureRate: (v, l) => `${v.toFixed(1)}% (${l})`,
  },
})

The built-in default formatters are also exported for direct use:

import { labelDeploymentFrequency, labelLeadTime, labelChangeFailureRate, labelMttr } from '@baphy/dora'

All default formatters use Intl.NumberFormat('en-US') with an explicit locale — output is consistent and predictable regardless of the runtime environment.

Performance

Benchmarked with vitest bench. Each metric function is a single O(n) pass. Reproduce locally:

npm run bench

calcDeploymentFrequency

| Input size | Mean time | |---|---| | 100 events | ~0.013 ms | | 1,000 events | ~0.12 ms | | 10,000 events | ~1.2 ms | | 100,000 events | ~13 ms |

calcLeadTime

| Input size | Mean time | |---|---| | 100 changes | ~0.008 ms | | 1,000 changes | ~0.073 ms | | 10,000 changes | ~0.73 ms | | 100,000 changes | ~9.1 ms |

calcChangeFailureRate

| Input size | Mean time | |---|---| | 100 events | ~0.005 ms | | 1,000 events | ~0.046 ms | | 10,000 events | ~0.46 ms | | 100,000 events | ~5 ms |

calcMttr

| Input size | Mean time | |---|---| | 100 incidents | ~0.007 ms | | 1,000 incidents | ~0.071 ms | | 10,000 incidents | ~0.71 ms | | 100,000 incidents | ~9.3 ms |

calcDora (all four metrics)

| Input size (each) | Mean time | |---|---| | 100 | ~0.03 ms | | 1,000 | ~0.27 ms | | 10,000 | ~2.7 ms |

License

MIT © pilmee