Skip to content

millionco/react-doctor-benchmarks

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

24 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

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 🟒 β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘ 96/100 0 12 8 529a54f
2 nodejs.org 🟒 β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘ 86/100 0 197 181 93fba76
3 tldraw 🟑 β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘ 71/100 7 146 76 d49babc
4 t3code 🟑 β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘ 69/100 0 753 255 d1e85c4
5 better-auth 🟑 β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘ 64/100 0 628 266 e637c7d
6 mastra 🟑 β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘ 63/100 23 499 215 ca6a039
7 excalidraw 🟑 β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ 62/100 1 558 179 f6d85bc
8 payload 🟑 β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ 60/100 4 766 424 d6b2d73
9 typebot 🟑 β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ 57/100 4 382 206 77fd228
10 medusajs/admin 🟑 β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ 56/100 10 591 247 25d82f3
11 plane 🟑 β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ 55/100 9 1947 833 50a7b47
12 rocket.chat 🟑 β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ 51/100 55 2191 968 80b0f14
13 twenty πŸ”΄ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ 48/100 83 1835 1242 62b347f
14 unkey πŸ”΄ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ 48/100 27 975 385 e6bae5f
15 shadcn/ui πŸ”΄ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ 46/100 15 2350 1014 c9930b7
16 trigger.dev πŸ”΄ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ 42/100 37 2047 626 55fa2d4
17 formbricks πŸ”΄ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ 38/100 11 4623 913 c172e2a
18 langfuse πŸ”΄ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ 36/100 23 3180 854 352cdf3
19 tooljet πŸ”΄ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ 33/100 190 5982 1459 4426a21
20 onlook πŸ”΄ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ 32/100 65 2034 416 a242be5
21 cal.com πŸ”΄ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ 31/100 43 1584 425 180ede2
22 sentry πŸ”΄ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ 30/100 181 3258 1679 e2424fd
23 appsmith πŸ”΄ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ 30/100 144 2455 1315 a128a3e
24 posthog πŸ”΄ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ 29/100 684 5511 1871 4885123
25 supabase πŸ”΄ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ 28/100 53 3312 1317 bde9d53
26 lobehub/lobe-chat πŸ”΄ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ 28/100 294 6833 1683 519e755
27 dub πŸ”΄ β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ 24/100 61 3418 1232 c4706da

Last updated 2026-05-18T07:44:21.969Z Β· react-doctor 0.1.6 Β· 27 scored, 0 skipped/failed Β· raw results in results/latest.json

How it works

  1. repos.yaml lists every benchmark target with its GitHub URL, the workspace project to scan, and any per-repo overrides (skip dead-code, skip install, etc.).
  2. The benchmark workflow fans out across the list using a matrix strategy. Each job clones one repo, attempts pnpm/npm/yarn/bun install --ignore-scripts (auto-detected from the lockfile), and runs npx -y react-doctor@latest <scanDir> --json --offline --fail-on none. If install fails, it falls back to --no-dead-code and scans the source anyway so a working score still lands.
  3. A final publish job downloads every per-repo artifact, writes results/latest.json, regenerates this README's leaderboard table, and commits the diff back to main using the default GITHUB_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.

About

React Doctor benchmarks

Topics

Resources

Stars

Watchers

Forks

Contributors