Routing pattern consistency
Why it matters
Next.js routing resolution between app/ and pages/ follows non-obvious precedence rules: App Router wins for matching segments, but Pages Router catches everything App Router does not claim. Deploying a half-migrated app can change which route renders simply because someone added or removed a file, with no local indication. SEO metadata, layouts, and data-fetching conventions differ completely between the two routers, producing broken canonical URLs and duplicated or missing OG tags.
Severity rationale
Medium because resolution ambiguity can swap which page renders at a given URL without any code change to that page.
Remediation
Finish the migration to App Router. Enumerate what remains:
find pages -type f -name "*.tsx" | grep -vE '_app|_document|_error|api/'
Move each remaining page into app/ (e.g., pages/about.tsx becomes app/about/page.tsx), port getServerSideProps to server components or route handlers, then delete the old file. Keep pages/api/ until those endpoints are migrated to app/api/ route handlers. Redeploy and verify every URL resolves through the expected router.
Detection
-
ID:
routing-pattern-consistency -
Severity:
medium -
What to look for: When the framework is Next.js, check whether BOTH
app/ANDpages/directories exist at the project root or undersrc/. Enumerate every file under each. Pages Router files (pages/index.tsx,pages/about.tsx, etc.) and App Router files (app/page.tsx,app/about/page.tsx, etc.) are mutually exclusive routing systems. EXCEPT: apages/directory containing ONLY_app.{tsx,jsx,ts,js},_document.{tsx,jsx,ts,js},_error.{tsx,jsx,ts,js}, ORpages/api/**files (legacy API routes are allowed alongside App Router) is acceptable. Count all non-allowed files inpages/whenapp/also exists. The threshold for failure is at least 1 non-allowlisted file in pages/ when app/ also has page files. -
Pass criteria: When framework is Next.js: only one routing system in active use, OR
app/is the active router ANDpages/only contains the allowlisted exception files. Report even on pass: "Routing pattern: App Router (or Pages Router). [N] route files." -
Fail criteria: Both
app/andpages/contain non-allowlisted route files — mid-migration state with unclear ownership. -
Skip (N/A) when: Framework is not Next.js OR only one of
app//pages/exists. -
Detail on fail:
"Both routing patterns active: app/ has 12 page files, pages/ has 5 page files (excluding _app, _document, api/). The two routers conflict — pick one and finish the migration." -
Remediation: Mixing App Router and Pages Router pages means each route's behavior depends on which router resolves it first — and Next.js's resolution rules are not obvious. Pick the destination and finish the migration:
# Inventory non-allowlisted pages/ files find pages -type f -name "*.tsx" | grep -vE '_app|_document|_error|api/' # Move each to app/ following the new conventions # pages/about.tsx → app/about/page.tsx # Then delete the pages/ file
Taxons
History
- 2026-04-18·v1.0.0·Initial import from ai-slop-code-drift·automated