react-doctor-benchmarks
May 11, 2026 ยท View on GitHub
Reproducible react-doctor scores for popular open-source React frontends.
The scores below are produced by GitHub Actions on a weekly cron (and on demand). Every entry is scanned with npx react-doctor@latest --json --offline against a fresh clone of the upstream repo, and the resulting JSON is committed alongside this README so the leaderboard is fully auditable.
Leaderboard
| Rank | Project | Score | Errors | Warnings | Files | Commit |
|---|---|---|---|---|---|---|
| 1 | executor | ๐ข โโโโโโโโโโโโโโโโโโโโ 94/100 | 3 | 10 | 8 | 8de3f4c |
| 2 | nodejs.org | ๐ข โโโโโโโโโโโโโโโโโโโโ 86/100 | 0 | 196 | 179 | 125b760 |
| 3 | tldraw | ๐ก โโโโโโโโโโโโโโโโโโโโ 70/100 | 7 | 145 | 76 | 8d2c9d8 |
| 4 | t3code | ๐ก โโโโโโโโโโโโโโโโโโโโ 68/100 | 0 | 765 | 256 | 6ab8f93 |
| 5 | better-auth | ๐ก โโโโโโโโโโโโโโโโโโโโ 64/100 | 0 | 628 | 266 | e21d744 |
| 6 | excalidraw | ๐ก โโโโโโโโโโโโโโโโโโโโ 63/100 | 1 | 555 | 177 | b2b2815 |
| 7 | mastra | ๐ก โโโโโโโโโโโโโโโโโโโโ 63/100 | 23 | 468 | 207 | 98c37f3 |
| 8 | payload | ๐ก โโโโโโโโโโโโโโโโโโโโ 60/100 | 4 | 768 | 424 | 419a8e3 |
| 9 | typebot | ๐ก โโโโโโโโโโโโโโโโโโโโ 57/100 | 4 | 382 | 206 | 85eb843 |
| 10 | plane | ๐ก โโโโโโโโโโโโโโโโโโโโ 56/100 | 9 | 1944 | 833 | 4c1bdd1 |
| 11 | medusajs/admin | ๐ก โโโโโโโโโโโโโโโโโโโโ 56/100 | 10 | 591 | 247 | 456b06f |
| 12 | rocket.chat | ๐ก โโโโโโโโโโโโโโโโโโโโ 51/100 | 57 | 2178 | 969 | c7de992 |
| 13 | twenty | ๐ด โโโโโโโโโโโโโโโโโโโโ 48/100 | 85 | 1833 | 1242 | c810199 |
| 14 | unkey | ๐ด โโโโโโโโโโโโโโโโโโโโ 48/100 | 27 | 968 | 381 | c262a0e |
| 15 | shadcn/ui | ๐ด โโโโโโโโโโโโโโโโโโโโ 46/100 | 15 | 2349 | 1014 | 8ca30ed |
| 16 | trigger.dev | ๐ด โโโโโโโโโโโโโโโโโโโโ 42/100 | 37 | 1943 | 593 | 567e2a2 |
| 17 | formbricks | ๐ด โโโโโโโโโโโโโโโโโโโโ 41/100 | 11 | 4056 | 811 | 1d18b5c |
| 18 | langfuse | ๐ด โโโโโโโโโโโโโโโโโโโโ 36/100 | 27 | 3176 | 854 | c1af23a |
| 19 | tooljet | ๐ด โโโโโโโโโโโโโโโโโโโโ 33/100 | 190 | 5976 | 1459 | f33ff86 |
| 20 | onlook | ๐ด โโโโโโโโโโโโโโโโโโโโ 32/100 | 65 | 2034 | 416 | a242be5 |
| 21 | cal.com | ๐ด โโโโโโโโโโโโโโโโโโโโ 32/100 | 43 | 1582 | 425 | fb01494 |
| 22 | posthog | ๐ด โโโโโโโโโโโโโโโโโโโโ 31/100 | 682 | 5440 | 1857 | 1be458f |
| 23 | appsmith | ๐ด โโโโโโโโโโโโโโโโโโโโ 31/100 | 145 | 2450 | 1314 | 893572e |
| 24 | supabase | ๐ด โโโโโโโโโโโโโโโโโโโโ 30/100 | 52 | 3305 | 1315 | 95d1e8a |
| 25 | sentry | ๐ด โโโโโโโโโโโโโโโโโโโโ 30/100 | 179 | 3194 | 1650 | 31da780 |
| 26 | lobehub/lobe-chat | ๐ด โโโโโโโโโโโโโโโโโโโโ 29/100 | 294 | 6606 | 1641 | 79ed4b5 |
| 27 | dub | ๐ด โโโโโโโโโโโโโโโโโโโโ 25/100 | 59 | 3367 | 1213 | 3d450c5 |
Last updated 2026-05-11T07:33:40.103Z ยท react-doctor 0.1.6 ยท 27 scored, 0 skipped/failed ยท raw results in results/latest.json
How it works
repos.yamllists every benchmark target with its GitHub URL, the workspace project to scan, and any per-repo overrides (skip dead-code, skip install, etc.).- The
benchmarkworkflow fans out across the list using a matrix strategy. Each job clones one repo, attemptspnpm/npm/yarn/bun install --ignore-scripts(auto-detected from the lockfile), and runsnpx -y react-doctor@latest <scanDir> --json --offline --fail-on none. If install fails, it falls back to--no-dead-codeand scans the source anyway so a working score still lands. - A final
publishjob downloads every per-repo artifact, writesresults/latest.json, regenerates this README's leaderboard table, and commits the diff back tomainusing the defaultGITHUB_TOKEN. If nothing changed (idempotent rendering), the commit step is a no-op.
The harness pins nothing about the upstream repos by default โ every entry tracks HEAD of its default branch, and the SHA actually scanned is recorded in each result row so any score is reproducible. To pin a specific commit, set the ref field on a repos.yaml entry to a branch, tag, or SHA.
Consuming the leaderboard
Every CI run writes results/leaderboard.json โ a slim, stable JSON blob that downstream repos can fetch and drop in. It mirrors react-doctor's LeaderboardEntry interface so a one-shot replacement is straightforward.
Stable URL (always main, always the latest run):
https://raw.githubusercontent.com/millionco/react-doctor-benchmarks/main/results/leaderboard.json
Schema:
interface ConsumerLeaderboard {
schemaVersion: 1;
generatedAt: string; // ISO 8601 UTC
doctorVersion: string | null; // e.g. "0.0.47"
source: { repo: string; path: string; docs: string };
entries: Array<{
slug: string; // "tldraw"
name: string; // "tldraw"
githubUrl: string; // "https://github.com/tldraw/tldraw"
packageName: string; // workspace project name passed via --project
score: number; // 0โ100
errorCount: number;
warningCount: number;
fileCount: number; // affectedFileCount in react-doctor's JsonReport
commitSha: string | null; // SHA we actually scanned
scannedAt: string;
}>; // sorted desc by score
}
Example: regenerate react-doctor's leaderboard-entries.ts from CI:
# .github/workflows/refresh-leaderboard.yml in millionco/react-doctor
name: refresh leaderboard
on:
schedule:
- cron: "0 7 * * 1" # one hour after react-doctor-benchmarks runs
workflow_dispatch:
jobs:
refresh:
runs-on: ubuntu-latest
permissions: { contents: write, pull-requests: write }
steps:
- uses: actions/checkout@v4
- name: fetch latest leaderboard
run: |
curl -sSfL \
https://raw.githubusercontent.com/millionco/react-doctor-benchmarks/main/results/leaderboard.json \
-o /tmp/leaderboard.json
- name: codegen leaderboard-entries.ts
run: node scripts/codegen-leaderboard.mjs /tmp/leaderboard.json \
> packages/website/src/app/leaderboard/leaderboard-entries.ts
- uses: peter-evans/create-pull-request@v6
with:
title: "chore: refresh leaderboard from react-doctor-benchmarks"
commit-message: "chore: refresh leaderboard"
branch: chore/refresh-leaderboard
Where scripts/codegen-leaderboard.mjs is whatever projection makes sense for your downstream โ typically:
// scripts/codegen-leaderboard.mjs
import { readFileSync } from "node:fs";
const data = JSON.parse(readFileSync(process.argv[2], "utf8"));
const rows = data.entries.map((e) => ` ${JSON.stringify({
name: e.name, githubUrl: e.githubUrl, packageName: e.packageName,
score: e.score, errorCount: e.errorCount, warningCount: e.warningCount,
fileCount: e.fileCount,
})},`).join("\n");
process.stdout.write(`// Auto-generated from ${data.source.repo} on ${data.generatedAt}\n` +
`export const RAW_ENTRIES = [\n${rows}\n];\n`);
The blob is rewritten on every CI run, so even when scores don't change the generatedAt timestamp does โ you can safely diff or skip in your downstream codegen.
Adding a project
Open a PR that adds an entry to repos.yaml. The schema is defined and validated in scripts/lib/config.ts:
- slug: my-project # kebab-case, must be unique
name: my-project # display name in the leaderboard
githubUrl: https://github.com/owner/repo
scanDir: apps/web # optional, default "."
project: "@my/web" # optional, passes --project to react-doctor
packageManager: pnpm # optional, auto-detected from lockfile
skipDeadCode: false # optional, true โ pass --no-dead-code
skipInstall: false # optional, true โ don't install (implies skipDeadCode)
Once merged, the entry shows up the next time the workflow runs (weekly cron, or click Run workflow on the benchmark action).
Reproducing locally
pnpm install
pnpm tsx scripts/benchmark-repo.ts dub # scan one entry
pnpm tsx scripts/aggregate.ts # collect results/per-repo/*.json โ results/latest.json
pnpm tsx scripts/render-readme.ts # splice into README between markers
Set REACT_DOCTOR_VERSION=1.2.3 to pin a specific upstream version (defaults to latest).
Layout
| Path | What |
|---|---|
repos.yaml | Benchmark targets (canonical source of truth). |
results/latest.json | Aggregated leaderboard data; auto-generated. |
results/per-repo/<slug>.json | Per-repo result; auto-generated. |
scripts/ | The harness (matrix prep, single-repo benchmark, aggregator, README renderer). |
.github/workflows/benchmark.yml | The automation. |
Credits
Thirteen of the entries (tldraw, excalidraw, twenty, plane, formbricks, posthog, supabase, onlook, payload, sentry, cal.com, dub, nodejs.org) were originally compiled by hand for the react.doctor/leaderboard page in millionco/react-doctor. This repo turns that snapshot into a self-updating, auditable benchmark and adds ten more popular OSS React apps.
License
MIT.