Skip to content

Next.js Middleware Not Triggering: Common Issues and Solutions

Middleware in Next.js provides powerful capabilities for handling requests before they reach your routes, but getting it to work correctly can sometimes be challenging. This article covers the most common reasons why middleware might not trigger and provides practical solutions.

Understanding Middleware Placement

The correct location for your middleware file depends on your Next.js version and project structure:

For Projects Without src Directory

Place middleware.js or middleware.ts in the root directory (same level as pages or app):

/myproject/
├── middleware.js
├── pages/ (or app/)
├── package.json
└── ...

For Projects With src Directory

Place the middleware file in the src directory:

/myproject/
├── src/
│   └── middleware.js
├── pages/ (or app/)
├── package.json
└── ...

WARNING

Some Next.js versions (particularly 13-15) have had inconsistencies in middleware location requirements. If your middleware isn't working in one location, try the other.

Version-Specific Considerations

Next.js 12.x and Below

For versions earlier than 12.2.2, you need to:

  • Name your file _middleware.js or _middleware.ts
  • Place it inside the pages directory

Next.js 13.x and Above (App Router)

Recent versions support the App Router, which may require middleware in different locations:

  • Try both root-level and src/ locations
  • Some versions work better with middleware at src/app/middleware.ts

Common Issues and Fixes

1. Incorrect File Naming

Ensure your file is named exactly:

  • middleware.js (JavaScript)
  • middleware.ts (TypeScript)

DANGER

Even small typos like "middelware" instead of "middleware" will prevent it from working.

2. Custom Page Extensions

If you've configured custom page extensions in next.config.js, your middleware might need to follow the same pattern:

javascript
// next.config.js
const nextConfig = {
  pageExtensions: ["page.tsx", "api.ts", "page.jsx"],
};

// Your middleware should be named:
// middleware.page.ts or middleware.api.ts

3. Static Exports (output: 'export')

Middleware does not work with static exports:

javascript
// next.config.js
// ❌ This will disable middleware
const nextConfig = {
  output: 'export',
};

// ✅ Remove output: 'export' for middleware to work
const nextConfig = {
  // distDir: './dist', // Optional custom dist directory
};

4. Matcher Configuration Issues

Ensure your matcher configuration correctly targets the desired routes:

javascript
// middleware.js
export const config = {
  // Match specific paths
  matcher: ['/test', '/dashboard'],
  
  // Or use a regex pattern
  // matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)']
};

5. Using the Wrong Export

Make sure you're using the default export for your middleware function:

javascript
// ✅ Correct
export default function middleware(request) {
  // Your middleware logic
}

// ❌ Incorrect (unless you have specific needs)
export function middleware(request) {
  // This might not work in some configurations
}

Debugging Tips

Check the Right Console

Middleware logs appear in your server terminal, not the browser console. Always check where your server is running for middleware logging.

Verification Example

Use this simple middleware to test if it's working:

javascript
// middleware.js
import { NextResponse } from 'next/server';

export default function middleware(request) {
  console.log('Middleware triggered for:', request.url);
  return NextResponse.next();
}

export const config = {
  matcher: '/test',
};

Testing Script

Create a simple test to verify middleware is working:

javascript
// test-middleware.js
const LOCALHOST_URL = "http://localhost:3000";

async function testMiddleware() {
  try {
    const response = await fetch(`${LOCALHOST_URL}/test`);
    console.log('Response status:', response.status);
  } catch (error) {
    console.error('Test failed:', error);
  }
}

testMiddleware();

Alternative to Middleware: Next.config.js Redirects

If you only need simple redirects, consider using next.config.js instead:

javascript
// next.config.js
const nextConfig = {
  async redirects() {
    return [
      {
        permanent: true,
        source: "/test",
        destination: "/",
      },
    ];
  },
};

export default nextConfig;

Version Upgrade Recommendation

If you're using an older version of Next.js (especially version 12 or below), consider upgrading to benefit from improved middleware functionality and better documentation:

bash
npm install next@latest react@latest react-dom@latest eslint-config-next@latest

Summary

Middleware not triggering in Next.js typically comes down to:

  1. Incorrect file location (root vs src directory)
  2. Wrong file naming (middleware.js vs _middleware.js)
  3. Configuration issues (pageExtensions, output: 'export')
  4. Version-specific requirements

By systematically checking these areas, you should be able to resolve most middleware triggering issues. When in doubt, consult the official Next.js middleware documentation for your specific version.