Vercel Edge Middleware not running: Next.js matcher diagnostic guide
Why Vercel Edge Middleware skips requests in Next.js, and how to check matcher rules, edge cache, and invocation limits before escalating.
19 Aug 2025, 13:12 UTC

Symptom: Vercel Edge Middleware skips requests in Next.js
Useful takeaway: when middleware does not run, the cause is usually a matcher that excludes the path, an edge cache serving a stored response, or an invocation limit. Start by adding a temporary marker header to the middleware and comparing response headers on matching versus non-matching paths.
Recognizable conditions
- Middleware never runs on any path.
- Middleware runs on some paths but not others.
- Middleware runs locally with
vercel devbut not in production. - Headers set by middleware are missing from the final response.
Cause and diagnostic table
| Symptom | Most likely cause | Quick confirm |
|---|---|---|
| Never runs on any path | Matcher missing, too narrow, or middleware file in the wrong location | Check export const config and file placement |
| Runs on some paths only | Matcher pattern does not include the affected path | Compare curl -I on a matched and unmatched path |
| Works locally, not in production | Edge cache or geo/IP differences between vercel dev and production | Disable cache temporarily and retest on a preview deployment |
| Middleware headers missing | Framework or platform headers overwrite middleware headers | Inspect full response headers and middleware return order |
| Stops after deploy or intermittent errors | Middleware duration, size, or invocation count limit | Review Vercel deployment logs and plan quota |
Ordered checks
1. Confirm middleware location and export
Next.js expects middleware to export a middleware function, commonly at src/middleware.ts or the project root next to app or pages. Exact placement depends on your Next.js version; verify the version’s documentation.
Example:
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
export function middleware(request: NextRequest) {
const response = NextResponse.next()
response.headers.set('x-middleware-test', '1')
return response
}
export const config = {
matcher: ['/dashboard/:path*', '/api/:path*'],
}
2. Inspect the matcher
Matcher patterns are root-relative. A leading slash and the :path* glob change which paths enter middleware. Omitting matcher means middleware runs for every route. If your path is /dashboard/settings, the pattern /dashboard alone may not match unless you use /dashboard/:path*.
3. Add a marker header and test locally
Run this in the project root. It requires the Vercel CLI, a logged-in session (vercel login), and a linked project (vercel link).
vercel dev
Then test matching and non-matching paths:
curl -I http://localhost:3000/dashboard
curl -I http://localhost:3000/about
Expected: the x-middleware-test header appears on /dashboard but not on /about if the matcher excludes it. Risk: vercel dev approximates edge behavior; geo headers and IP-based logic may differ from production.
4. Deploy to preview and compare headers
Deploy to a preview environment, then run:
curl -I https://.vercel.app/dashboard
Expected: the marker header is present. If it is absent, middleware did not run or the response was served from cache.
5. Check edge cache behavior
Inspect the Cache-Control header. A cached edge response can bypass middleware on repeat requests. For a test, temporarily set Cache-Control: no-store in the middleware response, redeploy to preview, and retest. This changes state; roll back by removing the header and redeploying.
6. Review invocation limits and logs
Vercel plans enforce middleware duration, size, and invocation count limits. Exceeding them can cause silent fallback or deploy/runtime errors. Check Vercel deployment logs and Analytics for the affected path. This requires access to the Vercel project.
Fixes tied to findings
- Matcher too narrow: update
config.matcherto include the missing path with root-relative patterns. - Wrong file location: move the middleware file to the expected location and redeploy.
- Cache bypass: avoid caching responses that depend on middleware; set
Cache-Controlappropriately and retest with caching disabled. - Headers overwritten: set headers on the response returned by middleware before returning it, and confirm no later middleware or platform header replaces them.
- Limit exceeded: reduce work inside middleware, move heavy logic to an edge function or API route, or review your plan quota.
Escalation criteria
- Marker header present locally but missing in production after cache is disabled: contact Vercel support with the deployment ID and affected paths.
- Logs show invocation errors or drops: include logs, timestamps, and request paths when escalating.
- You use middleware for security-critical access control: do not rely on it alone if responses are cacheable; move authorization to an uncacheable edge function or origin route.
Limitations and practical verification
vercel dev is not identical to the production edge network. Plan quotas change, so verify current limits in your Vercel plan and documentation. This guide assumes Next.js with Vercel Edge Middleware; other frameworks may behave differently.
Practical verification: deploy a preview with the marker header, run curl -I on a matching path, confirm the header appears only on matched routes, then remove the marker and redeploy.
Rollback: editing middleware and redeploying changes state. If a fix causes regressions, revert the middleware commit and redeploy the previous deployment from the Vercel dashboard.
Review note: this draft is based on general Vercel middleware behavior and has not been verified against the current Vercel platform or your specific plan. Confirm matcher syntax, cache rules, and limits in current Vercel documentation before applying to production.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.