React Router Static Analysis with roto-rooter
Quick start
rr # analyze all routes in current directory
rr app/routes/dashboard.tsx # analyze specific file
rr --fix # auto-fix issues
rr --dry-run # preview fixes
Example output:
[links] app/routes/dashboard.tsx:24:8
<Link to="/users">
[error] Link target "/users" does not match any route
[hydration] app/routes/dashboard.tsx:31:12
new Date()
[warning] new Date() without arguments returns the current time, which differs between server render and client hydration
-> Pass the current date from the loader to ensure server and client use the same value
1 error, 1 warning
Commands
rr [FILES...] # analyze files (default: all routes)
rr --check links,forms # run specific checks
rr --check all # run all checks (including optional)
rr --check defaults,drizzle # run default checks plus specific optional checks
rr --format json # JSON output
rr --root ./my-app # set project root
rr sql --drizzle # extract SQL queries from Drizzle ORM code
rr sql --drizzle --format json # SQL extraction with JSON output
Available checks
Default checks (run automatically):
- links - validates
<Link>, <NavLink>, redirect(), navigate(), and href props on any component exist as routes
- forms - validates Form action targets, field alignment between forms and actions, intent-based dispatch
- loader - detects loader data usage issues and
clientLoader/clientAction with server-only imports
- params - validates route params match definitions
- interactivity - detects disconnected dialogs ("Save" buttons that don't save, "Delete" buttons that don't delete, stub handlers)
- hydration - detects hydration mismatches (Date, Math.random, locale-dependent formatting, window access in render)
Optional checks (opt-in via --check):
- drizzle - validates database operations against Drizzle ORM schema (unknown tables/columns, missing required columns, null-to-notNull, invalid enum literals, type mismatches, auto-generated column writes, DELETE/UPDATE without WHERE,
sql<number> with aggregates)
Examples
# Check for broken links in a route file
rr app/routes/dashboard.tsx --check links
# Auto-fix all fixable issues in the project
rr --fix
# Get JSON output for CI integration
rr --format json
# Enable Drizzle ORM persistence checking (auto-discovers schema)
rr --check drizzle
# Drizzle checking with explicit schema path
rr --check drizzle --drizzle-schema src/db/schema.ts
# Extract SQL queries from Drizzle ORM code
rr sql --drizzle
# Extract SQL queries from a specific file
rr sql --drizzle app/routes/users.tsx
# SQL extraction with JSON output
rr sql --drizzle --format json
1---2name: roto-rooter3description: Static analysis for React Router applications. Use when building or debugging React Router apps to verify routes, links, forms, loaders, params, hydration patterns, and database persistence operations.4---56# React Router Static Analysis with roto-rooter78## Quick start910```bash11rr # analyze all routes in current directory12rr app/routes/dashboard.tsx # analyze specific file13rr --fix # auto-fix issues14rr --dry-run # preview fixes15```1617Example output:1819```20[links] app/routes/dashboard.tsx:24:821 <Link to="/users">22 [error] Link target "/users" does not match any route2324[hydration] app/routes/dashboard.tsx:31:1225 new Date()26 [warning] new Date() without arguments returns the current time, which differs between server render and client hydration27 -> Pass the current date from the loader to ensure server and client use the same value28291 error, 1 warning30```3132## Commands3334```bash35rr [FILES...] # analyze files (default: all routes)36rr --check links,forms # run specific checks37rr --check all # run all checks (including optional)38rr --check defaults,drizzle # run default checks plus specific optional checks39rr --format json # JSON output40rr --root ./my-app # set project root41rr sql --drizzle # extract SQL queries from Drizzle ORM code42rr sql --drizzle --format json # SQL extraction with JSON output43```4445## Available checks4647**Default checks** (run automatically):4849- **links** - validates `<Link>`, `<NavLink>`, `redirect()`, `navigate()`, and `href` props on any component exist as routes50- **forms** - validates Form action targets, field alignment between forms and actions, intent-based dispatch51- **loader** - detects loader data usage issues and `clientLoader`/`clientAction` with server-only imports52- **params** - validates route params match definitions53- **interactivity** - detects disconnected dialogs ("Save" buttons that don't save, "Delete" buttons that don't delete, stub handlers)54- **hydration** - detects hydration mismatches (Date, Math.random, locale-dependent formatting, window access in render)5556**Optional checks** (opt-in via `--check`):5758- **drizzle** - validates database operations against Drizzle ORM schema (unknown tables/columns, missing required columns, null-to-notNull, invalid enum literals, type mismatches, auto-generated column writes, DELETE/UPDATE without WHERE, `sql<number>` with aggregates)5960## Examples6162```bash63# Check for broken links in a route file64rr app/routes/dashboard.tsx --check links6566# Auto-fix all fixable issues in the project67rr --fix6869# Get JSON output for CI integration70rr --format json7172# Enable Drizzle ORM persistence checking (auto-discovers schema)73rr --check drizzle7475# Drizzle checking with explicit schema path76rr --check drizzle --drizzle-schema src/db/schema.ts7778# Extract SQL queries from Drizzle ORM code79rr sql --drizzle8081# Extract SQL queries from a specific file82rr sql --drizzle app/routes/users.tsx8384# SQL extraction with JSON output85rr sql --drizzle --format json86```