Skip to content

Next.js App Router: app/**/route.ts handlers produce 0 Route nodes, so cross-repo-intelligence finds no edges #759

Open

Description

@webface

Environment

  • codebase-memory-mcp 0.8.1 (ui variant), macOS arm64 (Apple Silicon)
  • Fleet of TypeScript repos indexed into one store with mode: full

Problem

Next.js App Router projects define HTTP endpoints via the file convention: app/api/**/route.ts exporting GET / POST / PUT / DELETE handler functions. These handlers are indexed as plain Function nodes, but zero Route nodes are extracted:

search_graph(project=..., label="Route")
→ {"total":0, "results":[], "hint":"No nodes with this label. Available labels: Function, Method, Class, Interface, Route, ..."}

Verified on two independent Next.js App Router codebases (one with ~20 route handlers under src/app/api/, including nested dynamic segments). Both index cleanly (~4k nodes) with correct call graphs — only route extraction is affected.

Because no Route nodes exist, index_repository(mode="cross-repo-intelligence", target_projects=["*"]) reports projects_scanned: N but 0 edges of every CROSS_* type, even though sibling repos in the store call these endpoints.

Expected

Route nodes derived from the file convention:

  • path from the directory structure relative to app/ (e.g. src/app/api/chatgpt/actions/route.ts → /api/chatgpt/actions), with [param] / [...slug] segments normalized
  • method from the export name (GET, POST, etc.)

App Router has been the Next.js default since v13, so this likely affects a large share of modern TS repos — the pages-style pages/api/*.ts convention may deserve the same treatment.

Related

Possibly also worth covering: Convex httpRouter registrations (http.route({ path, method, handler }) in convex/http.ts) are similarly not extracted as Route nodes — happy to split that into a separate issue if you prefer.

Adjacent existing reports for other frameworks: #678 (FastAPI), #686 (Fiber), #734 (Spring prefix), #292 (protocol-aware matching design).

Activity

  1. added
    bugSomething isn't working
    parsing/qualityGraph extraction bugs, false positives, missing edges
    priority/normalStandard review queue; useful PR with ordinary maintainer urgency.
    on Jul 3, 2026
  2. DeusData commented on Jul 3, 2026

    @DeusData
    Owner

    Thanks for the Next.js App Router report. Triage: route extraction / cross-repo intelligence under #592 and #398.

    app/**/route.ts handlers should emit Route nodes with method/path information, otherwise cross-repo matching has nothing to join against. The regression should cover at least GET/POST route handlers and dynamic path segments before matching is layered on top.

  3. added this to the 0.9.1-rc milestone on Jul 8, 2026
  4. added
    priority/highNeeds near-term maintainer attention; high-impact bug, regression, safety issue, or release blocker.
    and removed
    priority/normalStandard review queue; useful PR with ordinary maintainer urgency.
    on Sep 5, 2026
  5. petterip commented on Sep 16, 2026

    @petterip

    I'd like to contribute a focused fix for this, following the regression coverage you requested.

    For example, src/app/api/users/[id]/route.ts exporting GET and POST should produce GET /api/users/:id and POST /api/users/:id Route nodes, linked to their handlers.

    I propose deriving the path from the App Router directory structure and the method from each handler's export name during extraction. These would populate the existing handler route metadata, allowing the existing route-node pass to create the Route nodes and HANDLES edges.

    Regression coverage would include GET/POST, nested dynamic segments, catch-all paths, and handler changes/deletions during re-indexing. Cross-repo matching, Pages Router and other frameworks would remain separate.

    Would you be open to a PR implementing this approach?

  6. DeusData commented on Sep 25, 2026

    @DeusData
    Owner

    @petterip, thank you for offering to take this on, and sorry for the silence since the 16th. Yes, please go ahead with the approach you described: derive the path from the App Router directory and the method from each exported handler name, fill the existing handler route metadata, and let the route-node pass create the Route nodes and HANDLES edges.

    There's a close precedent you can copy: SvelteKit's file-convention routes in src/pipeline/pass_route_nodes.c (sveltekit_file_kind / sveltekit_route_path). They already map [param] → :param and [...slug] → *slug, strip (group) segments, and give the Route nodes the handler's file_path. Please do the same, so that search_graph --file-pattern works on them (see #1366).

    The regression list you gave is exactly right: GET/POST, nested dynamic segments, catch-all, and handler change/delete across a re-index. Keeping Pages Router, Convex and cross-repo matching out of scope is the right call too. export const GET = async () => … handlers are already indexed as Function nodes on current main, so there's something to link to. Thanks again for the careful proposal, and thanks @webface for the original report!

  7. DeusData commented on Oct 19, 2026

    @DeusData
    Owner

    Thank you again for the App Router proposal. The September reply already approved the focused route-extraction approach and its regression scope. I have no new implementation result to add; if there is an existing draft, please link it here so the work stays connected to the original report.

  8. petterip commented on Oct 20, 2026

    @petterip

    Written with AI assistance (Claude Code); I reviewed it and stand behind it.

    Thanks @DeusData. Linking the work as you asked: #2738 is the groundwork PR. On every index the route pass rebuilds each handler's Route from its stored route_path, which it read with a quote scan, so an App Router directory with a quote in its name would get a second Route cut at the quote and HANDLES properties that are not valid JSON. #2738 makes the route pass read and write those properties as valid JSON, with five regression tests that fail on main without it.

    The App Router change itself is #2747, stacked on #2738 and using the approach you approved. The path comes from the directory and the method from the exported handler name, both filled into the existing handler route metadata. The route-node pass then creates the Route nodes (with the handler's file_path) and the HANDLES edges. Its regressions cover GET/POST, nested dynamic segments, catch-all, and handler change/delete across a re-index. Pages Router, Convex and cross-repo matching stay out of scope.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingparsing/qualityGraph extraction bugs, false positives, missing edgespriority/highNeeds near-term maintainer attention; high-impact bug, regression, safety issue, or release blocker.

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions