react-brain
Browse decisions
React & language foundations 3App architecture 9UI 12Platform & native 9Build, test, observe, secure 6AI in React apps 3stack composerdecision recordscensusstaleness bencharchitecturechangelogmethodologyroadmap

entriestooling-ops · verified 2026-07-10 · react + react-native

Developer experience — CI, lint/format, hooks, monorepo, onboarding

reviewedconfidence: highthis tier holds 75% on the public scorecard (6/11 graded · 0 overturned) →

related decisions: build · security · ai-devtools

re-verified 3× — 2026-07-13 · 2026-07-10 · 2026-07-06 · changelog

recommendation

Gate tests + typecheck + lint on every PR in CI, and enforce the same locally with a pre-commit hook. For lint/format, default to Biome (one fast tool) unless you need ESLint's plugin ecosystem (react-hooks, react-compiler).

  • has tests but no CI → add CI FIRST; invariants that aren't gated silently rot (a real finding in audited production apps)
  • needs ESLint react-hooks / react-compiler rules → ESLint flat config + Prettier over Biome
  • multi-package repo → pnpm workspaces + Turborepo for a cached task graph
  • normative styleguide but no linter config → wire the rules into lint so they're enforced mechanically, not by review
  • lots of agent-written React landing in the repo → add a react-doctor pass (CI or agent skill) on top of lint

Options & tradeoffs

the field considered — and why each one isn’t the default here

optiontradeoffevidence
CI (GitHub Actions / similar)gate tests + typecheck + lint + build on every PR; the single highest-leverage DX baseline
lint/format — Biome or ESLint (flat) + PrettierBiome = one fast Rust tool (lint+format); ESLint flat + Prettier = bigger plugin ecosystem (react-hooks, react-compiler rules)8.8M/wk · ships in 1/34
git hooks — husky + lint-staged / lefthookrun lint/format/tests pre-commit/pre-push; catch issues before CI30.5M/wk · ships in 11/34
monorepo task runner — Turborepo / Nx + pnpm workspacescached, parallel task graph across packages (see RB-E-BUILD)17.8M/wk · ships in 2/34
dependency hygiene — renovate/dependabot + auditautomated updates + npm/pnpm audit + install-script blocking (see RB-E-SECURITY)
react-doctor (Million)npx react-doctor — one-shot codebase scan for React footguns (state/effects/perf/a11y/security), CI mode + installable as an agent skill; 13.5k★, from the Million.js/react-scan team; positioned as the lint layer for agent-written React (see RB-E-AI-DEVTOOLS)731k/wk

evidence: npm weekly downloads (signals snapshot) · “ships in n/D” = adoption across the production-app census, honest denominators

npm weekly downloads (from the corpus's last signals run): husky 30.5M · lefthook 2.9M · @biomejs/biome 8.8M · eslint 141.9M · prettier 99.2M · lint-staged 25.0M · turbo 17.8M · nx 7.5M · lunte 5k · react-doctor 731k

Verified notes

DX is cross-cutting — architecture/boundaries depth → engineering-principles; bundler choice → RB-E-BUILD; supply-chain → RB-E-SECURITY. This entry is the feedback loop (CI/lint/hooks/onboarding) that keeps the others honest.

Canonical reading

Editorial annotations on why each piece matters — the articles themselves are the originals; read them there.

Best CI/CD for mobile apps in 2026: a practical comparisonExpo (VENDOR — comparing its own EAS Workflows)

The only structured selection matrix for mobile CI platforms (EAS Workflows vs Bitrise vs Codemagic vs GitHub Actions): fingerprint-based repack turning 10–15min builds into ~2min JS-only builds, and GHA macOS runners measured ~2.4x slower than Codemagic M4s. READ AS A VENDOR DOC — Expo wins its own comparison; the evaluation axes (runner hardware, cache strategy, fingerprint/repack) are the durable part.

Expo without EAS: scaling the React Native DX of an app with 90M+ usersDoctolib

Large-scale case study adopting Expo's bare workflow (not EAS) with fingerprint caching + JS patching to halve CI builds and grow contributors 9→105. A durable enterprise RN build/CI-DX blueprint.

Sources

Depth (in-domain rules) is owned by the engineering-principles skill — this entry is selection breadth.

The full explanation

The reviewed long-form essay behind this entry — the why, not a how-to. Also on GitHub.

About developer experience — CI, lint/format, hooks, monorepo

Diataxis: Explanation. This page builds understanding of the DX feedback loop — the reasoning behind the picks. It is not a setup guide. Architecture/boundary depth is owned by engineering-principles; bundlers by RB-E-BUILD; supply chain by RB-E-SECURITY. Read this for the why.

The one principle that organises everything: an invariant you don't gate is a suggestion

DX isn't comfort — it's the feedback loop that keeps every other decision honest. Every quality property you care about (tests pass, types check, lint is clean, the bundle stays under budget) is either mechanically enforced or it silently rots. The organising principle is therefore brutal and simple: mechanize your invariants. A styleguide nobody lints is a wish; a test suite CI doesn't run is decoration; a "we always typecheck" that isn't gated is a story you tell until the day it isn't true. So the DX question is never "which tools are nice" — it's "what must always be true, and what gate makes it always true?"

The default, and why

Gate tests + typecheck + lint on every PR in CI, and enforce the same locally with a pre-commit hook. For lint/format, default to Biome (one fast tool) unless you need ESLint's plugin ecosystem (react-hooks, react-compiler).

CI on every PR is the single highest-leverage DX baseline — it's the gate that turns invariants from aspiration into fact. The pre-commit hook is the cheap copy of that gate: catch the obvious failures locally so they never burn a CI cycle (and never land). Biome is the default linter/formatter because it's one fast Rust tool doing lint+format with near-zero config; you switch to ESLint flat config + Prettier specifically when you need its plugin ecosystem — notably the react-hooks and react-compiler rules, which are load-bearing in the compiler era (RB-E-REACT-CORE).

The landscape, and when each piece earns its place

CI (GitHub Actions / similar) — the gate. Tests + typecheck + lint + build on every PR. The non-negotiable baseline; everything else is optimization around it.

Lint/format — Biome vs ESLint(flat)+Prettier — Biome for speed and simplicity (one tool); ESLint+Prettier for the plugin ecosystem (react-hooks, react-compiler, jsx-a11y, import rules). The axis is "do I need specific ESLint plugins?" — if not, Biome.

Git hooks — husky + lint-staged / lefthook — the local pre-commit/pre-push gate. Run lint/format/affected-tests before code leaves the machine. It's the fast feedback that makes the CI gate rarely fail.

Monorepo task runner — Turborepo / Nx + pnpm workspaces — a cached, parallel task graph so a many-package repo builds and tests incrementally (RB-E-BUILD). The thing that keeps CI fast as the repo grows.

Dependency hygiene — renovate/dependabot + audit — automated updates plus npm/pnpm audit and install-script blocking. This is where DX and security meet (RB-E-SECURITY); keeping deps current and locked-down is a feedback loop too.

Tradeoffs and failure modes to name out loud

  • Tests but no CI. A real finding in audited production apps: a suite exists but nothing gates it, so invariants quietly rot. Add CI first — it's higher-leverage than any new test.
  • A styleguide that isn't wired into lint. Normative rules enforced by code review are enforced inconsistently and expensively; mechanize them so review can focus on design.
  • Skipping the local gate. Relying only on CI makes the loop slow and noisy; a pre-commit hook catches the trivial failures for free.
  • Biome vs ESLint as identity, not need. Pick on whether you need ESLint's plugins (react- hooks/react-compiler), not on tribe. Many teams want those rules — that's a real reason to keep ESLint.
  • Monorepo without a task graph. Running everything on every change doesn't scale; cache and parallelize (Turborepo/Nx) or CI time balloons.

How it interacts with the rest of the stack

  • Build (RB-E-BUILD). The monorepo task graph and bundler choice are the build side of the same loop; DX is the gating/feedback side.
  • Testing (RB-E-TESTING). Tests only protect you if CI runs them — testing tooling and the CI gate are two halves of one mechanism.
  • Security (RB-E-SECURITY). Dependency automation + install-script blocking is shared ground; supply-chain hardening lives in this loop.
  • Architecture depth (engineering-principles). Module boundaries, dependency direction, and what-may-import-what are owned there; DX is how you enforce such rules mechanically.

In one paragraph

DX is the feedback loop that keeps every other choice honest, and its one principle is mechanize your invariants: an unenforced rule is a suggestion. So gate tests + typecheck + lint in CI on every PR, mirror it with a pre-commit hook for fast local feedback, default lint/format to Biome (switch to ESLint+Prettier when you need react-hooks/react- compiler plugins), and scale a monorepo with pnpm + Turborepo. If an app has tests but no CI, adding CI is the highest-leverage move available — and dependency automation ties this loop to RB-E-SECURITY.


See also: RB-E-BUILD (monorepo task graph, bundlers), RB-E-TESTING (CI gates the suite), RB-E-SECURITY (dependency hygiene / supply chain). Architecture/boundary depth: the engineering-principles skill.

Related in tooling-ops: build · testing · observability · security · ota