Hassan Agmir Hassan Agmir

Middlewares in Next.js

Hassan Agmir
Middlewares in Next.js

Introduction

Next.js is a powerful React framework that simplifies building full-stack applications. One of its standout features is middlewares, which allow developers to execute logic before a request is completed. Middlewares are crucial for authentication, redirection, rate limiting, logging, and more.

In this comprehensive guide, we’ll explore:

  • What middlewares are in Next.js
  • How to create and use them
  • Use cases and best practices
  • Performance considerations
  • Error handling in middlewares

By the end, you'll have a solid understanding of Next.js middlewares and how to use them effectively in your applications.

What Are Middlewares in Next.js?

Middlewares in Next.js are functions that run before a request is completed, allowing you to modify the request, response, or even redirect the user. They run on Edge Runtime, meaning they execute closer to the user, improving performance.

Key Features of Next.js Middleware:

  1. Runs before request completion: Middlewares intercept the request before rendering a page or API route.
  2. Executes on Edge Runtime: Middleware runs in a lightweight execution environment without the need for a full Node.js server.
  3. Modify requests and responses: You can transform headers, cookies, or request parameters.
  4. Supports conditional execution: You can define matchers to specify which routes the middleware applies to.
  5. Works with Next.js API Routes & Pages: It applies to both frontend and backend aspects of your app.

When to Use Middleware in Next.js?

Middleware is useful in various scenarios, including:

  • Authentication & Authorization: Protect specific routes and validate users.
  • Geo-Localization: Redirect users based on their location.
  • A/B Testing & Feature Flags: Show different experiences to different users.
  • Rate Limiting & Security: Prevent abuse by limiting requests per user.
  • Custom Headers & Response Modification: Modify request/response headers before they reach the client.

How to Create and Use Middlewares in Next.js

Creating middleware in Next.js is straightforward. It involves defining a middleware.ts or middleware.js file at the root of your project.

Step 1: Setting Up Middleware

Create a middleware.ts file in the root of your Next.js project.

import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
    console.log('Middleware running...');
    return NextResponse.next();
}
  • NextRequest: Represents the incoming request object.
  • NextResponse.next(): Allows the request to proceed without changes.
  • console.log('Middleware running...'): Logs every time middleware executes.

Step 2: Applying Middleware to Specific Routes

You can define matchers in next.config.js to specify which routes should run the middleware.

module.exports = {
  matcher: ['/dashboard/:path*', '/profile/:path*']
};

This ensures that middleware runs only for /dashboard and /profile routes.

Step 3: Modifying the Response

Middleware can modify the request or response. For example, adding security headers:

export function middleware(request: NextRequest) {
    const response = NextResponse.next();
    response.headers.set('X-Custom-Header', 'Middleware Enabled');
    return response;
}

Common Middleware Use Cases

1. Authentication & Authorization Middleware

Restrict access to authenticated users.

export function middleware(request: NextRequest) {
    const token = request.cookies.get('authToken');
    if (!token) {
        return NextResponse.redirect('/login');
    }
    return NextResponse.next();
}

2. Geo-Localization Middleware

Redirect users based on their country.

export function middleware(request: NextRequest) {
    const country = request.geo?.country || 'US';
    if (country === 'FR') {
        return NextResponse.redirect('/fr');
    }
    return NextResponse.next();
}

3. Rate Limiting Middleware

Limit API requests per IP address.

const rateLimit = new Map();

export function middleware(request: NextRequest) {
    const ip = request.ip || '0.0.0.0';
    const now = Date.now();

    if (rateLimit.has(ip) && now - rateLimit.get(ip) < 1000) {
        return new NextResponse('Too Many Requests', { status: 429 });
    }

    rateLimit.set(ip, now);
    return NextResponse.next();
}

4. Feature Flag Middleware

Enable A/B testing for specific users.

export function middleware(request: NextRequest) {
    const userId = request.cookies.get('userId');
    const isBetaUser = userId && userId.startsWith('beta-');
    return NextResponse.rewrite(isBetaUser ? '/beta-dashboard' : '/dashboard');
}

Performance Considerations

Middleware in Next.js runs on Edge Runtime, which offers benefits but also limitations:

Pros:

Low latency - Runs closer to users. ✅ Fast execution - No full Node.js server needed. ✅ Scalable - Works well with serverless functions.

Cons:

Limited APIs - No native file system access. ❌ Cold starts - Might be slow for first requests. ❌ Size Limits - Edge functions have strict size constraints.

To optimize middleware performance:

  • Avoid blocking operations (e.g., database calls).
  • Use caching for frequently accessed data.
  • Minimize dependencies to keep execution lightweight.

Error Handling in Middleware

Handling errors properly is crucial to avoid breaking the request flow.

export function middleware(request: NextRequest) {
    try {
        // Your logic here
        return NextResponse.next();
    } catch (error) {
        console.error('Middleware Error:', error);
        return new NextResponse('Internal Server Error', { status: 500 });
    }
}

Conclusion

Next.js middleware is a powerful tool for handling authentication, security, localization, and more. By understanding how it works and applying best practices, you can significantly enhance your Next.js applications.

Key Takeaways:

  • Middleware runs before requests are complete, allowing modification or redirection.
  • It executes on Edge Runtime, making it lightweight and performant.
  • Useful for auth, geo-location, rate limiting, and feature flags.
  • Optimize performance by avoiding blocking operations and minimizing dependencies.
  • Implement proper error handling to ensure robustness.

Mastering middleware in Next.js will enable you to build secure and high-performance applications. 

Subscribe to my Newsletters

Stay updated with the latest programming tips, tricks, and IT insights! Join my community to receive exclusive content on coding best practices.

© Copyright 2025 by Hassan Agmir . Built with ❤ by Me