I’m experiencing an issue where all dynamic API routes in my Next.js App Router project return 404 on Vercel, despite building successfully and appearing in the Functions list.
Environment
Next.js version: 15.4.7
Router: App Router
Production URL:https://paideia-sigma.vercel.app
Framework detected: Next.js (auto-detected after removing vercel.json)
Local development: Works perfectly with npm run dev
Current behavior: On Vercel, all dynamic API routes (/api/[param]), e.g. /api/quiz/4w4EHpNCtGXv0CDCM52T and /api/test-dynamic/123, return the static 404 page (X-Matched-Path: /404) with no function logs. Static routes like /api/health and /api/test-simple work.
Expected behavior: Dynamic API routes should match their functions (they’re listed in Functions) and return JSON.
The pattern is clear: routes without dynamic segments [param] work fine, but any route with a dynamic segment returns 404.
Steps to reproduce:
Hit https://paideia-sigma.vercel.app/api/health → 200 JSON.
Hit https://paideia-sigma.vercel.app/api/test-dynamic/123 → 404 page, X-Matched-Path: /404, no logs.
Same for /api/quiz/.
Key observations:
Routes work perfectly locally with npm run dev
Routes appear in the Functions list in Vercel dashboard
Build logs show successful compilation
Response headers show X-Matched-Path: /404
No function execution logs are generated when accessing dynamic routes on Vercel
Removed vercel.json - no change
Middleware only matches /admin/*
Why would all dynamic API routes return 404 while static routes work, despite successful builds and the routes appearing in the Functions list? Is this a known issue with Next.js 15.4.7 or is there a configuration problem I’m missing?
and ofc the routes work perfectly locally with npm run dev. Let me know if there are any questions, I vibe coded this so I will try my best to answer. This is also my first deployment so I’m learning as much as I can.
Yes, but in my app I’m accessing quizzes by ID via /api/quiz/[id]. For example: /api/quiz/4w4EHpNCtGXv0CDCM52T.
I should’ve specified, I’m not trying to match /api/quiz without an ID, only /api/quiz/[id]. My problem is even though there are no segments after id, it still doesn’t work with just /api/quiz/[id] and it’s driving me crazy.
Locally, hitting /api/quiz/4w4EHpNCtGXv0CDCM52T works; on Vercel it returns the static 404 page (X-Matched-Path: /404) with no function logs, even though this route is listed in Functions.
I tried something new:
The App Router handler is a catch‑all at the end of the path: src/app/api/quiz/[…segments]/route.ts with:
I’m not hitting /api/quiz without an ID; only /api/quiz/{id}. Static APIs like api/health work; any dynamic API (/api/quiz/{id}) 404s the same way.
Given the catch‑all is at the end of the path and the route exists in Functions, why is router resolving /api/quiz/ to /404 on this deployment?? Thank you
Hey there, @yaokevinl-7218! I saw you mentioned deploying on Google Cloud Run without issues. Just checking in to see if you still need help with the Vercel dynamic API route problem or if you found a solution. Let me know!