Next.js Middleware Routing Error Solved - Real Troubleshooting Guide
How I fixed a Next.js middleware file naming issue that caused all routes to return 404 errors. Includes error logs, code analysis, and step-by-step solution.
Next.js Middleware Routing Error Solved
Introduction
Middleware is a core component in Next.js that handles routing logic. But when it doesn't work correctly, every page returns a 404 error.
This post documents a real Next.js middleware routing issue I encountered and how I solved it. If you're facing a similar problem, I hope this helps.
Environment
| Item | Value |
|---|---|
| OS | Windows 11 |
| CPU | AMD Ryzen 7 7800X3D |
| RAM | 32GB |
| Runtime | Node.js v20.5.0 |
| Framework | Next.js 14.2.5 |
| Language | TypeScript 5.3 |
| i18n | next-intl 3.0 |
Problem
I was using next-intl for multi-language support and SEO. With localePrefix: 'as-needed', English pages were at root (/), other languages at prefixed paths (ko/, es/, ja/).
Suddenly, all pages started returning 404 errors.
Initial Symptoms
GET /calorie-calculator β 404 Not Found
GET /blog β 404 Not Found
GET /about β 404 Not FoundOnly the root path / worked. Every other path returned 404.
Root Cause Analysis
First Suspect: i18n Configuration
I checked next.config.js:
// next.config.js
const createNextIntlPlugin = require('next-intl/plugin');
const withNextIntl = createNextIntlPlugin('./i18n/request.ts');
module.exports = withNextIntl({
reactStrictMode: true,
images: {
formats: ['image/avif', 'image/webp'],
},
});The configuration looked correct. But I needed to verify if createNextIntlPlugin was working properly.
Second Suspect: Middleware File Location
Next.js expects middleware.ts in the root directory. But I found the file was named proxy.ts:
// Wrong structure
/src
/app
...
/lib
...
proxy.ts β This was acting as middleware
// Correct structure
/src
/app
...
/lib
...
middleware.ts β Must be in rootNext.js automatically detects middleware.ts during build. If it's named differently, Next.js won't recognize it as middleware.
Error Log
> Build error occurred
Error: Encountered an unknown middleware. Please ensure it exports a default function.
at C:\Users\...\node_modules\next\dist\build\index.js:1847:23
at process.processTicksAndRejections (node:internal/process/task_queues:95:5)Solution Process
Step 1: Rename File
First, I renamed proxy.ts to middleware.ts:
# PowerShell command
Rename-Item -Path "proxy.ts" -NewName "middleware.ts"After renaming, I ran the build again:
npm run buildBut the error persisted. The file name alone wasn't enough.
Step 2: Analyze Middleware Code
I examined the middleware.ts code:
import createMiddleware from 'next-intl/middleware';
const locales = ['en', 'ko', 'es', 'ja'];
const defaultLocale = 'en';
export default createMiddleware({
locales,
defaultLocale,
localePrefix: 'as-needed',
});
export const config = {
matcher: ['/((?!api|_next|.*\\..*).*)'],
};The code itself looked fine. But I suspected localePrefix: 'as-needed'.
Step 3: Analyze Routing Matching
localePrefix: 'as-needed' doesn't add prefixes for English:
/en/aboutβ redirects to/about/ko/aboutβ stays at/ko/about
But there was a problem. The matcher pattern /((?!api|_next|.*\\..*).*) was catching all paths including /about.
Step 4: Understand Next.js Routing Priority
I researched Next.js routing priority:
- Static files in
public/ - Build artifacts in
_next/static/ - Pages in
pages/orapp/ - Routing logic in
middleware.ts
The issue was that middleware was intercepting all routes. Without NextResponse.rewrite(), Next.js couldn't find the path and returned 404.
Step 5: Add Rewrite Logic
The solution was to add NextResponse.rewrite() in middleware:
import { NextRequest, NextResponse } from 'next/server';
import createMiddleware from 'next-intl/middleware';
const locales = ['en', 'ko', 'es', 'ja'];
const defaultLocale = 'en';
const intlMiddleware = createMiddleware({
locales,
defaultLocale,
localePrefix: 'as-needed',
});
export function middleware(request: NextRequest) {
const { pathname } = request.nextUrl;
// Handle English locale
if (pathname.startsWith('/en/')) {
return NextResponse.redirect(
new URL(pathname.replace('/en', ''), request.url),
{ status: 301 }
);
}
// Handle regular paths (default English)
if (pathname !== '/' && !locales.some(locale => pathname.startsWith(`/${locale}/`))) {
return NextResponse.rewrite(
new URL(`/${defaultLocale}${pathname}`, request.url),
{ headers: { 'x-next-intl-locale': defaultLocale } }
);
}
return intlMiddleware(request);
}
export const config = {
matcher: ['/((?!api|_next|.*\\..*).*)'],
};Results
After the fix, I ran the build and tested:
$ npm run build
β Compiled successfullyTest Results
| Path | Before | After |
|---|---|---|
| `/calorie-calculator` | 404 | 200 |
| `/blog` | 404 | 200 |
| `/about` | 404 | 200 |
| `/ko/about` | 404 | 200 |
| `/es/blog` | 404 | 200 |
Lessons Learned
What I Learned
File name matters: Next.js middleware must be named
middleware.ts. Any other name won't work.Routing priority: Next.js has routing priorities. If middleware intercepts all routes without
rewrite(), static files or page routing gets ignored.Importance of rewrite:
NextResponse.rewrite()rewrites paths so Next.js can find the correct page.i18n interaction:
localePrefix: 'as-needed'skips prefixes for English, but middleware needs logic to handle this.
Better Solutions
If I had done these, the problem could have been avoided:
Use correct file name from start: Using
middleware.tsfrom the beginning would prevent this issue.Check next-intl docs: Reading the middleware setup examples in next-intl documentation would have solved it faster.
Unit testing: Unit tests for middleware routing would have caught the issue earlier.
Related Documentation
Conclusion
Next.js middleware is powerful, but a single misconfiguration can break the entire application. The problems covered in this post are common errors, and understanding the troubleshooting process helps deepen understanding of Next.js routing mechanics.
I hope this helps developers facing similar issues.
This post was written on 2025-07-25. Some content may differ if the technology stack versions have changed.
This blog does not accept any external sponsorships, affiliate marketing, or ad revenue. All analyses and recommendations are based purely on personal experience and official documentation.
For bug reports or technical questions, please submit via GitHub Issues.