Skip to content

App Router resolves to app/app, an empty build-artifact directory: the frontend compiles zero routes #515

Description

@Xhristin3

Problem

The Next.js app router resolves to app/app — a directory whose only tracked file is a build artifact, app/app/.next/analyze/summary.json — so every real page and route handler in the repository compiles to nothing. Verified with Next.js's own resolver from app/:

findPagesDir: { pagesDir: undefined, appDir: '/workspaces/XStreamRoll/app/app' }

next/dist/lib/find-pages-dir.js resolves the app directory with findDir(dir, 'app'), which prefers ./app over ./src/app:

function findDir(dir, name) {
    // prioritize ./${name} over ./src/${name}
    let curDir = _path.default.join(dir, name);
    if (_fs.default.existsSync(curDir)) return curDir;
    curDir = _path.default.join(dir, 'src', name);
    ...
}

The app/app directory exists (its only tracked content is the committed bundle-analyzer baseline app/app/.next/analyze/summary.json), so Next never reaches app/src/app, where the real pages live. app/app contains no page.tsx, no layout.tsx, and no route handlers.

The consequence is total: next build emits only Next's auto-generated _not-found and _global-error slots — app/.next/server/app-paths-manifest.json contains exactly those two entries — so the built frontend serves a blank app. Every tracked page is outside the compiled router:

  • app/page.tsx, app/layout.tsx, app/auth/login/page.tsx, app/auth/register/page.tsx, app/api/auth/* route handlers
  • app/src/app/page.tsx, app/src/app/dashboard/**, app/src/app/admin/**, app/src/app/api/health/route.ts, app/src/app/providers.tsx

The CI bundle-analysis job (bundle-analysis in .github/workflows/ci.yml) builds the app and checks bundle sizes with node .github/scripts/check-bundle-size.js — but the budgets are upper bounds (BUNDLE_BUDGET_TOTAL / BUNDLE_BUDGET_PER_LARGEST), so an empty build of ~0 bytes passes. The regression is invisible to CI.

Root cause

app/                                  # Next project root (next.config.mjs, package.json)
├── app/                              # ← resolves as the app router; contains only .next/
│   └── .next/analyze/summary.json    #   committed bundle-analyzer baseline
├── src/app/                          # ← the real pages (dashboard, admin, auth-adjacent, api/health)
└── page.tsx, layout.tsx, auth/, api/ # ← pre-src layout leftovers, also outside the router

Why this is architecturally hard

  1. There are two incompatible layout generations in the tree: the pre-src layout (app/page.tsx, app/layout.tsx, app/auth/*, app/api/auth/* at the project root) and the src/app layout (app/src/app/**). Fixing the resolution is not enough — the two must be reconciled into one canonical layout, or the fix lands on top of a still-inconsistent tree.
  2. app/layout.tsx imports ./src/app/providers — a cross-directory dependency that only makes sense in the pre-src world. If src/app becomes the router, a root layout.tsx must be created inside src/app (there is none today), and the pre-src leftovers (page.tsx, layout.tsx, auth/, api/auth/*) must be moved or deleted; if the project root becomes the router instead, src/app/** must be moved up. The issue's deliverable is a single, buildable layout — the direction is a design decision.
  3. The committed artifact app/app/.next/analyze/summary.json is what creates the shadowing directory in the first place. Whatever the chosen layout, the stray app/app directory must not exist at build time, and the bundle-analysis baseline (which .github/scripts/check-bundle-size.js writes into <appDir>/.next/analyze/summary.json) needs a home that cannot shadow the router.
  4. CI cannot catch this today (empty bundle passes the budget check). Part of the fix is making the build gate real: assert a minimum bundle size or assert that the expected routes exist in the build output.

Proposed design

Choose one canonical layout and migrate everything into it, e.g.:

  • Delete the stray app/app directory (including the committed .next/analyze/summary.json baseline) so findDir falls through to app/src/app; create app/src/app/layout.tsx (moving the root layout's providers/theme/toaster wiring); move app/auth/* and app/api/auth/* into app/src/app/ (or delete them if superseded); delete the orphaned app/page.tsx and app/layout.tsx.

Or keep the root as the router and move src/app/** up — but the src/app layout is where the recent work lives, so consolidating on src/app is the lower-friction direction.

Acceptance criteria

Build

  • cd app && npm run build succeeds and app/.next/server/app-paths-manifest.json contains real routes: /, /auth/login, /auth/register, /dashboard/streams, /admin, and the /api/health route handler.
  • The app router resolution (node -e "require('next/dist/lib/find-pages-dir').findPagesDir(process.cwd())" from app/) returns a directory that contains page.tsx and layout.tsx.
  • No directory named app/app exists in the repository after the fix.

CI

  • The bundle-analysis job fails (or a new assertion fails) when the build emits zero pages — add a minimum-total-bytes assertion in .github/scripts/check-bundle-size.js or an equivalent route-presence check.
  • npm run analyze output is written to a location that cannot shadow the app router.

Tests

  • cd app && npm run test passes after the layout consolidation (any page that referenced @/lib/... or @/components/... from the moved layout keeps working).

Documentation

  • README.md's "Package Breakdown" / run instructions still match the layout actually built (e.g. the app runs from app/src/app routes).

Out of scope

Rebuilding the auth flow or any individual page — those are separate issues (the auth flow is tracked separately and depends on this one landing first). This issue is only about making the frontend build and serve real routes again.

Getting started

Real files in scope: app/app/.next/analyze/summary.json (delete or relocate), app/src/app/ (add layout.tsx, move auth/ pages and api/auth/* handlers in), app/page.tsx, app/layout.tsx (remove or move), .github/scripts/check-bundle-size.js (add a lower bound), .github/workflows/ci.yml (bundle-analysis job).

Verify with:

cd app && npm run typecheck && npm test && npm run build
ls app/.next/server/app-paths-manifest.json   # must list the real routes

Good first files to read: app/layout.tsx, app/src/app/providers.tsx, app/src/app/dashboard/streams/page.tsx, .github/scripts/check-bundle-size.js.

Metadata

Metadata

Assignees

Labels

GrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardThird CampaignCampaign: Third CampaignarchitectureStructural design decisionsbugSomething isn't workingfrontendRelated to app/ Next.js frontendhigh impact

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions