react-doctor Scores Your AI-Generated React, Then Teaches Your Agent to Stop Writing It
Your AI Writes Terrible React? This 8,000+ Star Open-Source Tool Can Catch 90% of "Agent Spaghetti Code"
Vibe Coding has been hot for over half a year now. Almost every colleague around me has an AI coding agent—Claude Code, Cursor, Codex—busily churning out business logic every day.
The efficiency is real. But so are the problems.
Last week I reviewed a PR a colleague generated with Claude Code. It contained a useEffect with an empty dependency array, yet inside it used a closure variable to update state. That means this code runs once when the component mounts and then never responds to data changes again. The compiler doesn't error. TypeScript doesn't error. ESLint wasn't configured with that rule—so it quietly slipped into the main branch.
Honestly, I do this kind of thing myself all the time. AI-written React code works, but doesn't hold up under scrutiny. Messy state management, unnecessary re-renders, closure traps, memory leaks, terrible accessibility… AI agents won't proactively tell you about these issues, and by the time you discover them, they're often already in production.
So when I saw react-doctor, my first reaction was: finally, someone built this.
What is it?
In one sentence: react-doctor is a React code health scanner, purpose-built to cure the bad React that AI writes.
The first line of its GitHub README says:
Your agent writes bad React. This catches it.
Blunt, brutal—my kind of style.
Its workflow is simple too—run one command in your project root:
npx -y react-doctor@latest .
It then scans your entire codebase, gives you a health score from 0 to 100, and lists every issue it finds.
- 75+ points: Great — solid code quality
- 50-74 points: Needs work — requires improvement
- Below 50 points: Critical — you'd better fix this immediately
This scoring system feels a lot like Lighthouse, which is very intuitive for frontend developers.
As of today (May 2026), react-doctor already has 8,000+ stars on GitHub, gaining 200+ stars daily—strong momentum. The team behind it is millionco, the same team that built Million.js and React Compiler. They started with React performance optimization, so their understanding of "bad React" runs deep at an industrial level.
Quick Start
Zero-config setup, just run it in your project:
npx -y react-doctor@latest .
Supports Next.js, Vite, React Native. It auto-detects your framework type and React version, and the rule set automatically toggles based on the environment. If you're on a Next.js project, it enables SSR-related checks; if React Native, it activates mobile-specific rules.
First run on one of my own Next.js projects: scored 62, Needs work. It listed 40+ issues across five dimensions: state management, performance, security, accessibility, and dead code. Honestly, worse than I expected, but better than I feared.
Core Feature Breakdown
react-doctor's checks cover six major dimensions:
1. State & Effects
This is where AI stumbles most often. Typical issues it catches include:
- Cascading setState: calling
setStatefor two different states inside oneuseEffect, each triggering a separate re-render - Derived state: using one state variable to store the computed result of another state, purely wasting re-renders
- Calling setState during render: directly causing infinite loops
- Closure traps: incomplete
useEffectdependency arrays leading to stale closures
For example, this kind of code AI frequently writes gets flagged:
// ❌ react-doctor: no-derived-useState
const [items, setItems] = useState(data);
const [filtered, setFiltered] = useState([]);
useEffect(() => {
setFiltered(items.filter(i => i.active));
}, [items]);
Switching to a useMemo saves an extra re-render:
// ✅
const [items, setItems] = useState(data);
const filtered = useMemo(() => items.filter(i => i.active), [items]);
2. Performance
This area checks for unnecessary re-renders, optimizable useMemo/useCallback usage, large list rendering, and more.
Interestingly, it not only checks where you didn't add useMemo, but also where you shouldn't have. Because blindly adding useMemo also carries overhead—react-doctor's rules are fairly judicious here.
3. Architecture
Unreasonable component splitting, deep props drilling, giant components with unclear responsibilities—these are disaster zones for AI-generated code. Agents tend toward "it works" and basically don't care about maintainability.
4. Security
XSS risks, improper use of dangerouslySetInnerHTML, etc. AI often reaches for dangerouslySetInnerHTML to save effort, and react-doctor highlights these spots.
5. Accessibility
Missing aria-label, inappropriate role attributes, autofocus abuse, and so on. This category has a lower default weight, but you can increase it if you care about a11y.
6. Dead Code
Components or exports never used, or conditional branches that are always false. AI-generated code frequently leaves behind this kind of "code debris."
Every diagnostic comes with a filename, line number, and fix suggestion. It doesn't just tell you "there's a problem here" and leave it at that—it tells you why it's a problem and how to fix it.
CI/CD Integration: Block Bad Code at the Gate
Scanning once to find problems is nice, but automatically checking every PR is even better. react-doctor provides GitHub Actions integration:
name: React Doctor
on:
pull_request:
push:
branches: [main]
permissions:
contents: read
pull-requests: write
jobs:
react-doctor:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
- uses: millionco/react-doctor@main
with:
diff: main
github-token: ${{ secrets.GITHUB_TOKEN }}
Once configured, every PR triggers an automatic scan of changed files (not the entire codebase), and it comments any React issues it finds directly on the PR. You can also set fail-on: warning to make CI fail red when warning-level issues appear—bad code doesn't even get through the door.
No GitHub Actions? No problem. A simple npx command works in any CI:
npx -y react-doctor@latest --fail-on warning
Pairing with AI Agents: From "Cure" to "Prevention"
This feature I think is the coolest—react-doctor isn't just a "post-hoc scanning" tool; it can be installed directly into your AI coding agent, teaching the agent how to write good React from the start.
npx -y react-doctor@latest install
After running, it detects the AI agents installed on your machine (Claude Code, Cursor, Codex, OpenCode, and 50+ others), then asks which one you want to install into. Add --yes to skip the prompt.
Once installed, react-doctor injects itself as Agent Skills into the agent's workflow. When the agent generates React code, it follows the rules defined by react-doctor—essentially giving your AI a "coach" for React best practices.
After installing it into Claude Code, the quality of generated React code noticeably improved. At minimum, useEffect dependency arrays stopped being sloppy, and it no longer called setState directly during render. It feels like installing a "quality gate" inside the AI's brain.
Flexible Configuration, Adjust as Needed
Not every rule applies to your project. react-doctor's configuration system is designed practically:
{
"ignore": {
"rules": ["react/no-danger"],
"files": ["src/generated/**"],
"overrides": [
{
"files": ["components/modules/diff/**"],
"rules": ["react-doctor/no-array-index-as-key"]
}
]
}
}
Three levels, from coarse to fine:
- ignore.rules: globally disable a specific rule
- ignore.files: disable all rules for an entire directory/file (use sparingly)
- ignore.overrides: disable only specific rules for specific files (recommended)
You can also integrate your existing ESLint config (.eslintrc.json or .oxlintrc.json), and react-doctor automatically merges those rules into its scoring system.
Code-level ignores are also supported:
// react-doctor-disable-next-line react-doctor/no-cascading-set-state
useEffect(() => {
setA(value);
setB(value);
}, [value]);
These design choices align closely with the ESLint ecosystem, so the learning curve is nearly zero.
Competitor Comparison
When it comes to React code quality tools, ESLint + eslint-plugin-react-hooks is the most common combo. But they have two core problems:
- ESLint doesn't give you a health score. With dozens of warnings, you don't know which ones are truly serious.
- eslint-plugin-react-hooks only covers hooks rules. It does nothing for performance, architecture, accessibility, or dead code.
Biome/Oxlint's React rule coverage is broader, but they are fundamentally Linters, not Doctors. A linter tells you where syntax/patterns are wrong; a doctor tells you whether your code is healthy. These are two different mental models.
react-doctor's value isn't in checking a few extra rules—it's in quantifying "React code quality." You say "our React code quality is decent"—where's the evidence? Run react-doctor once: 75 points is decent, 45 points is not. This quantified conversation is extremely useful in team collaboration, especially when you need to convince a boss/PM to allocate time for code quality improvements.
Moreover, react-doctor automatically merges your existing ESLint/Oxlint config, so you don't need to abandon your current lint workflow—just layer a health assessment on top of it.
Usage Impressions
After about a week of use, a few honest thoughts:
The good:
- Zero-config startup is genuinely pleasant. One
npxcommand and you're running—no fiddling with rule configuration for ages. - Diagnostic messages are clear. Every issue comes with a specific file, line number, and fix suggestion—not the "figure it out yourself" style.
- Agent Skills mode is a genuinely differentiating feature. Teaching AI how to write good React is smarter than post-hoc checking.
- CI integration is smooth. The PR comment format lets team reviews focus on code logic rather than code quality issues.
- Framework detection is accurate. It auto-detected my Next.js project and enabled SSR-related rules.
The not-so-great:
- First scan speed isn't fast. My medium-sized project (300+ components) took about 30+ seconds. Faster than a full TypeScript check, but I still hope future versions optimize this.
- Some rules have a high false-positive rate. For example, the "unnecessary useMemo" rule misjudges in scenarios with complex type inference.
- Accessibility checks are fairly basic. If you have rigorous a11y requirements, you'll still need professional tools like axe-core alongside it.
Recommendation Score: ⭐⭐⭐⭐ (4.5/5)
The 0.5 deduction is mainly for speed and false-positive rate, which is entirely acceptable for a recently released v1.x.
Who It's For
- Heavy AI coding users (daily Claude Code/Cursor/Codex users): basically a must-install tool. Agent Skills mode can significantly reduce your review burden.
- React project Tech Leads: the CI-integrated "PR quality gate" is very useful, turning code quality standards into concrete practice.
- Teams currently working on React projects: tools that quantify code quality are rare. react-doctor's health score carries great value in team communication.
- Beginners / developers transitioning to React: the fix suggestions attached to every diagnostic are very friendly—essentially an on-demand "React best practices mentor."
Who It's Less Suited For
- Projects that already have a very thorough ESLint + Biome + axe-core combo, with strictly enforced team code standards—the marginal benefit here will be smaller.
react-doctor solves a real pain point of the AI coding era: Agents can write React, but they can't write good React. Unlike traditional linters that merely list rule violations one by one, it delivers an experience closer to a "code review feel"—giving an overall health score, telling you which area is weakest, and suggesting how to fix it.
Currently at 8,059 stars, MIT license. Project link:
👉 https://github.com/millionco/react-doctor
If your project is already using AI agents to write React, I strongly recommend running this. You'll discover a mountain of spaghetti code—but at least you'll know how tall it is.