Remix v2 Routing Code Review
SkillFiles & storageReviews Remix v2 route files for naming convention violations, missing layouts, resource-route shape, and v1 holdovers. Use when reviewing files under app/routes/ in a Remix v2 codebase.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Remix v2 Routing Code Review skill
What this skill tells your AI
The instructions your AI receives, as published by existential-birds/beagle in plugins/beagle-react/skills/remix-v2-routing-review/SKILL.md and read by ahel’s review.
Loaded by review-remix-v2 (umbrella) to flag routing anti-patterns in app/routes/ modules. See remix-v2-routing for canonical patterns.
Quick Reference
| Issue Type | Reference |
|---|---|
Filename smells (index.tsx, __auth, wrong escape, non-route files) | references/route-files.md |
Missing <Outlet />, orphan dotted segments, duplicated layout logic | references/layouts-outlets.md |
Default export on a resource, <Link> without reloadDocument, splat params | references/resource-routes.md |
react-router-dom imports, __double folders, v1-adapter fallback | references/v1-holdovers.md |
Missing <Meta />/<Links />/<Scripts />/<ScrollRestoration />, Vite-vs-Classic <LiveReload />, root ErrorBoundary without document shell | references/root-shell.md |
Scope
This skill flags issues in:
- Files under
app/routes/(filenames, exports, imports, JSX shape) app/root.tsx(document shell, root<Outlet />)remix.config.js(entries that change route discovery:routes(),ignoredRouteFiles,@remix-run/v1-route-convention)- Any module that links to a resource route (
<Link>usage)
Out of scope: loader/action data contracts (covered by remix-v2-data-flow-review), form behavior (remix-v2-forms-review), meta/headers (remix-v2-meta-sessions-review).
Review Checklist
- Index routes named
_index.tsx, notindex.tsx - Pathless layouts use single underscore (
_auth.tsx), not double (__auth/) - Dotted child routes (
users.profile.tsx) have a parent module or use trailing underscore (users_.profile.tsx) - Parent route modules render
<Outlet /> - Splat segments read
params["*"], neverparams.splat/params.rest - Literal dots/special chars escaped with brackets (
sitemap[.]xml.tsx) - Resource routes have no
defaultexport -
<Link>to a resource route usesreloadDocument(or is a plain<a>) - Imports come from
@remix-run/react, notreact-router-dom - Non-route files (CSS, helpers, tests) live in a folder with
route.tsx, or are listed inignoredRouteFiles - Trailing-underscore opt-outs only used when a parent layout actually exists to escape
- Optional segments
($lang)narrowparams.langin the loader (see references/route-files.md)
Valid Patterns (Do NOT Flag)
- Resource route with no default export — this is the convention that makes it a resource route. Never flag.
- Any
_-prefixed pathless layout file without<Outlet />when the module is intentionally a wrapper that renders fixed UI only. Confirm by checking children — if no*.{segment}.tsxsiblings exist, the wrapper-only shape is intentional. - Files prefixed with
_that don't appear in any URL — pathless layouts and_indexare supposed to be hidden from the URL. @remix-run/v1-route-conventionwired up inremix.config.js— legitimate migration adapter, not a smell on its own. Only flag if v1-style files appear without the adapter installed.useLoaderData<typeof loader>()— type annotation, not assertion.- Splat route accessing
params["*"]with bracket syntax — that is the only correct access pattern. - Folder
app/routes/dashboard/withroute.tsxplus sibling.server.ts,.css, component files — co-location is the documented pattern. - Trailing underscore (
concerts_.mine.tsx) when a siblingconcerts.tsxlayout exists and this URL intentionally skips it.
Context-Sensitive Rules
Only flag these issues when the specific context applies:
| Issue | Flag ONLY IF |
|---|---|
index.tsx under app/routes/ | Project is v2 and @remix-run/v1-route-convention is NOT wired in remix.config.js |
Parent module without <Outlet /> | Sibling dotted children (parent.*.tsx) exist in app/routes/ |
__double underscore folder | No v1-convention adapter is installed |
| Trailing-underscore segment | No corresponding parent layout exists (nothing to opt out of) |
| Default export on a module returning non-HTML | The loader/action actually returns a raw Response (PDF, JSON, RSS) |
<Link> to resource route | Target route has no default export AND <Link> lacks reloadDocument |
Hard gates (before writing findings)
Run these in order. Do not draft user-facing findings until every gate passes for the batch you are about to report.
-
Location evidence — Pass: Each issue lists a repo path (file under
app/routes/orremix.config.js) and either a line range or a short verbatim quote from the file you read. Filename-only smells must quote the literal filename. -
Exemption check — Pass: For each issue, state in one line why it is not covered by Valid Patterns (Do NOT Flag). Resource-route flags require explicit evidence of a
defaultexport or a<Link>withoutreloadDocument. -
Version check — Pass: Confirm the project is Remix v2 (check
package.jsonfor@remix-run/react^2, or presence of v2 flat-routes filenames elsewhere inapp/routes/). If@remix-run/v1-route-conventionis wired inremix.config.js, v1 filenames (__auth/,index.tsx) are intentional — do not flag them as smells. -
Protocol — Pass: Complete the Pre-Report Verification Checklist in review-verification-protocol for this review.
When to Load References
- Reviewing filenames under
app/routes/→ references/route-files.md - Reviewing parent modules and shared chrome → references/layouts-outlets.md
- Reviewing a module that returns non-HTML, or any
<Link>to such a module → references/resource-routes.md - Reviewing imports or filenames that look like v1 → references/v1-holdovers.md
- Reviewing
app/root.tsx(document shell,<Meta />/<Links />/<Scripts />/<ScrollRestoration />,<LiveReload />on Vite vs Classic Compiler, rootErrorBoundary) → references/root-shell.md
Review Questions
- Does every parent route render
<Outlet />, or is it a deliberate wrapper-only? - Do filenames match the v2 grammar (single
_for pathless,_indexfor index,[...]for escapes)? - Are resource routes free of
defaultexports, and do all<Link>s to them usereloadDocument? - Are all router imports from
@remix-run/react(and server helpers from@remix-run/node)? - If v1 filenames exist, is
@remix-run/v1-route-conventionwired up — or are they accidental?
Additional Documentation
- Route file naming smells: references/route-files.md —
index.tsx,__doublefolders, wrong escape syntax, dot/underscore confusion, non-route files underapp/routes/. - Layouts and outlets: references/layouts-outlets.md — pathless layout misuse, missing
<Outlet />, orphan dotted children, duplicated layout logic. - Resource routes: references/resource-routes.md — accidental default export,
<Link>withoutreloadDocument, splatparams["*"]access. - v1 holdovers: references/v1-holdovers.md —
react-router-domimports,__authfolders,@remix-run/v1-route-conventionas a deliberate-vs-accidental tell.
Signals
- GitHub stars
- 81
- Forks
- 8
- Last commit
- Aug 2026
Advanced
- Catalog kind
- skill
- Gateway key
remix-v2-routing-review- Source
- github.com/existential-birds/beagle