At most one client-side router
Why it matters
Running react-router-dom inside a Next.js app creates two URL-state systems that fight each other: Next.js's file-based router owns actual page transitions while react-router's BrowserRouter intercepts client-side navigation within its subtree. Back-button behavior becomes unpredictable, useRouter and useNavigate report different current paths, and server-rendered pages hydrate with mismatched route state. Shared links often render the wrong page on cold load.
Severity rationale
High because hydration mismatches and conflicting route state break deep-linking and SEO on framework apps.
Remediation
Remove the third-party router and migrate to the framework's built-in routing. In a Next.js app that means converting every react-router-dom import site.
// Before
import { Link, useNavigate } from 'react-router-dom'
// After
import Link from 'next/link'
import { useRouter } from 'next/navigation'
Move routed components into app/ directory segments, then npm uninstall react-router-dom react-router. Verify every <a> and programmatic navigation uses Next primitives by checking src/components/ for stragglers.
Detection
-
ID:
dual-router -
Severity:
high -
What to look for: Apply the three-condition rule against this exact router allowlist:
react-router,react-router-dom,@tanstack/react-router,wouter,@reach/router,found. Treatreact-router+react-router-domas a single React Router unit. Count all routers from the allowlist that meet the three conditions (at least 3 importing files each). EXCEPT: if the framework is Next.js, Nuxt, SvelteKit, Remix, or Astro, the framework provides its own router and adding ANY of the above is a drift signal — fail if any are present alongside the framework router. EXCEPT: if the framework is none of the above (plain React SPA), one router from the allowlist is fine. -
Pass criteria: 0 client-side routers from the allowlist for framework projects (Next.js/Nuxt/SvelteKit/Remix/Astro), OR 0-1 client-side routers for plain React SPAs. Report even on pass: "Canonical router: [framework router name OR client router name OR 'none']."
-
Fail criteria: Framework provides routing AND a client-side router is also actively used, OR plain React project AND 2 or more client-side routers from the allowlist.
-
Skip (N/A) when: Project is server-only (no React, no JSX, project type is
apionly). -
Detail on fail:
"Framework is Next.js (built-in router) but 'react-router-dom' is also imported in 8 files. Pick one — Next.js routing or react-router, not both." -
Remediation: Two routers means two URL state systems, two link components, two ways to navigate. For framework projects (Next.js etc.), always use the framework's built-in routing:
// Bad: react-router-dom inside a Next.js app import { Link } from 'react-router-dom' // Good: use Next.js routing import Link from 'next/link'Remove the third-party router and migrate all
<Link>anduseNavigate()calls to the framework equivalents.
Taxons
History
- 2026-04-18·v1.0.0·Initial import from ai-slop-code-drift·automated