· Michał Roman · General  · 4 min read

Next.js middleware use cases

If you're using Next.js and haven’t played with middleware yet, you're missing out on some really clever and efficient ways to handle logic between a request and your app’s response.

Next.js middleware use cases

If you’re using Next.js and haven’t played with middleware yet, you’re missing out on some really clever and efficient ways to handle logic between a request and your app’s response. Most devs reach for middleware for the usual suspects: auth checks, redirects, or internationalization. But what if I told you there’s way more potential hiding in there?

Let’s dig into some creative, under-the-radar use cases for Next.js middleware that might just save you a headache—or spark your next feature idea.

Feature flags without external tools

You don’t need to pull in LaunchDarkly or build a full-featured feature flag service for basic needs. middleware can inspect cookies or headers and quietly toggle features before the page ever loads.

Here’s how you might gate a new dashboard redesign for internal users only:

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

export function middleware(req: NextRequest) {
  const url = req.nextUrl.clone();

  // Check for internal flag in cookies
  const isInternalUser = req.cookies.get('internal_user')?.value === 'true';

  // Redirect to old dashboard if not internal
  if (url.pathname.startsWith('/dashboard-new') && !isInternalUser) {
    url.pathname = '/dashboard';
    return NextResponse.redirect(url);
  }

  return NextResponse.next();
}

This way, you don’t need to ship two versions or build toggle logic in your app UI. middleware handles it before rendering.

A/B testing without third-party services

Middleware is also great for rolling out A/B tests. You can randomly assign a variant in the request, set a cookie, and route accordingly—all without touching the client-side logic.

Here’s an example:

export function middleware(req: NextRequest) {
  const url = req.nextUrl.clone();
  const abCookie = req.cookies.get('ab-test');

  let variant = abCookie?.value;

  if (!variant) {
    variant = Math.random() < 0.5 ? 'A' : 'B';
    const res = NextResponse.next();
    res.cookies.set('ab-test', variant);
    return res;
  }

  if (url.pathname === '/pricing') {
    url.pathname = variant === 'A' ? '/pricing-a' : '/pricing-b';
    return NextResponse.rewrite(url);
  }

  return NextResponse.next();
}

Boom, instant A/B testing with zero client-side overhead.

Dynamic theming via headers

Imagine theming your app not by the user’s preference stored in a DB, but by custom headers—for instance, when embedding your app into partner websites. middleware can read headers like x-theme and serve different styles.

export function middleware(req: NextRequest) {
  const theme = req.headers.get('x-theme');
  const url = req.nextUrl.clone();

  if (theme && url.pathname === '/') {
    url.pathname = `/themes/${theme}`;
    return NextResponse.rewrite(url);
  }

  return NextResponse.next();
}

The client sees their styled version without any JavaScript logic. It just works—server-side.

Locking out legacy browsers (or bots)

Tired of supporting ancient browsers or random scrapers ruining your analytics? middleware can sniff out user agents and reject—or route elsewhere—accordingly.

export function middleware(req: NextRequest) {
  const userAgent = req.headers.get('user-agent') || '';
  const isIE = userAgent.includes('MSIE') || userAgent.includes('Trident');

  if (isIE) {
    return new NextResponse('Internet Explorer is not supported.', { status: 403 });
  }

  return NextResponse.next();
}

Or take it further and redirect bots to lightweight versions of your pages to reduce bandwidth costs.

Geo-specific experiences without client-side Geo IP

Want to localize or regionalize content but skip heavy client-side geolocation APIs? middleware has built-in access to geo data via req.geo.

export function middleware(req: NextRequest) {
  const { country } = req.geo || {};

  if (country === 'DE') {
    const url = req.nextUrl.clone();
    url.pathname = `/de${url.pathname}`;
    return NextResponse.rewrite(url);
  }

  return NextResponse.next();
}

This way, German users see /de/home instead of just /home, and you don’t rely on the browser to figure it out.


middleware in Next.js isn’t just for auth guards and redirects. With a little creativity, you can offload tons of logic to the edge layer and keep your app fast and clean. Whether it’s lightweight A/B testing, regional experiences, or clever user targeting, middleware has your back.

So next time you find yourself adding yet another client-side condition or server route, take a second and ask: could this be done better with middleware?

The answer is probably yes.

Back to Blog

Related Posts

View All Posts »

Advanced Tailwind tips and tricks

Unlock Tailwind CSS's potential with advanced tips, dynamic sizing, responsive layouts, and more to enhance your web development workflow