Next.js Middleware Patterns erklärt: Routing, Auth und Rewrites
AI generated
</>
{ }
React · Next.js · Middleware · Edge Runtime
Next.js Middleware Patterns erklärt
Routing, Auth und Rewrites vor dem Rendering

Next.js Middleware läuft, bevor eine Route überhaupt gerendert wird, und entscheidet über Redirects, Rewrites und Header, noch bevor Server Components oder Client Components aktiv werden. Wer Matcher-Regeln, Auth-Checks und die Grenzen der Edge Runtime versteht, baut Routing-Logik, die schnell bleibt und trotzdem robust funktioniert.

18 Min. Lesezeit Matcher · Auth · Rewrites · Geolocation Next.js 14/15 · App Router

1. Was ist Next.js Middleware und wann greift sie

Next.js Middleware ist eine einzelne Datei, middleware.ts im Projekt-Root, die vor jedem Request in der Edge Runtime ausgeführt wird, noch bevor eine Route gematcht, ein Cache gelesen oder eine Server Component gerendert wird. Anders als eine Route Handler-Funktion, die eine eigene Antwort erzeugt, sitzt Next.js Middleware als Schicht davor: Sie kann einen Request durchlassen, umleiten, umschreiben oder mit zusätzlichen Headern versehen. Diese Position im Request-Lifecycle macht sie zum richtigen Ort für Entscheidungen, die für viele Routen gleichzeitig gelten.

Der zentrale Unterschied zu klassischem serverseitigem Routing liegt darin, dass Next.js Middleware nicht pro Seite konfiguriert wird, sondern global mit einer Matcher-Regel greift. Ein Auth-Check, eine Sprachumleitung oder ein Feature-Flag lassen sich damit an einer einzigen Stelle implementieren, statt in jeder einzelnen page.tsx wiederholt zu werden. Genau diese Zentralisierung ist der eigentliche Wert von Next.js Middleware: weniger Duplikation, ein einziger Ort für Cross-Cutting-Concerns.

Wichtig ist die Reihenfolge im Next.js-Modell: Middleware läuft vor dem Routing-Layer, hat aber keinen Zugriff auf das vollständige Node.js-Ökosystem, weil sie standardmäßig in der Edge Runtime ausgeführt wird. Das bedeutet, Next.js Middleware eignet sich hervorragend für schnelle, zustandslose Entscheidungen anhand von Request-Headern, Cookies oder der URL, aber nicht für schwere Datenbankabfragen oder Node-spezifische Bibliotheken. Diese Einschränkung wird in Abschnitt sechs im Detail behandelt.

2. Middleware Matcher Config: Pfade gezielt filtern

Ohne eine Matcher-Konfiguration läuft Next.js Middleware standardmäßig für praktisch jeden Request, inklusive statischer Assets, was unnötigen Overhead erzeugt. Der exportierte config-Block mit einem matcher-Array grenzt genau ein, für welche Pfade die Middleware überhaupt ausgeführt wird. Ein präziser Matcher spart nicht nur Rechenzeit, sondern verhindert auch, dass die Middleware versehentlich auf interne Next.js-Routen wie _next/static oder Bildoptimierungs-Endpunkte zugreift und dort unerwünschte Seiteneffekte auslöst.

Matcher-Patterns unterstützen sowohl einfache Pfad-Präfixe als auch vollständige Regex-Ausdrücke über die path-to-regexp-Syntax, mit der auch Negative Lookaheads möglich sind. Das erlaubt, gezielt alles außer bestimmten Pfaden zu matchen, etwa alles außer API-Routen und statischen Dateien. Bei komplexeren Next.js Middleware Setups mit mehreren unabhängigen Zuständigkeiten, etwa Auth für den Adminbereich und Geolocation für den Checkout, lohnt es sich, innerhalb der einen Middleware-Funktion nach Pfad-Prefix zu verzweigen, statt mehrere Middleware-Dateien zu simulieren, die es in Next.js technisch gar nicht gibt.


// middleware.ts — matcher config excludes static assets and API internals
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
  const { pathname } = request.nextUrl;

  // Branch by path prefix inside a single middleware function
  if (pathname.startsWith('/admin')) {
    return handleAdminAuth(request);
  }
  if (pathname.startsWith('/checkout')) {
    return handleCheckoutGeo(request);
  }

  return NextResponse.next();
}

function handleAdminAuth(request: NextRequest) {
  const token = request.cookies.get('session')?.value;
  if (!token) {
    return NextResponse.redirect(new URL('/login', request.url));
  }
  return NextResponse.next();
}

function handleCheckoutGeo(request: NextRequest) {
  return NextResponse.next();
}

// Negative lookahead: match everything except static files and API routes
export const config = {
  matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
};

Ein häufiger Fehler bei der Matcher-Config ist ein zu weit gefasstes Muster wie matcher: ['/:path*'], das jede Anfrage inklusive Bild-Requests durch die Next.js Middleware schickt. Das kostet nicht nur Latenz, sondern kann bei Cookie-Manipulationen oder Redirect-Logik auch zu Endlosschleifen führen, wenn eine Umleitung selbst wieder gematcht wird. Ein sauberer Matcher ist deshalb kein kosmetisches Detail, sondern eine Grundvoraussetzung für stabile Next.js Middleware.

3. Authentifizierung und Redirects in der Middleware

Der mit Abstand häufigste Anwendungsfall für Next.js Middleware ist der Schutz ganzer Routenbäume vor unauthentifizierten Zugriffen. Statt in jeder Server Component einen Session-Check zu wiederholen, liest die Middleware das Session-Cookie, validiert ein JWT oder ruft einen leichten Auth-Endpunkt auf, und leitet bei fehlender Berechtigung sofort mit NextResponse.redirect() um, bevor überhaupt Rendering-Arbeit investiert wird. Das spart Serverzeit und verhindert, dass geschützte Inhalte kurzzeitig im initialen HTML sichtbar werden.

Ein wichtiger Aspekt bei Next.js Middleware und Auth ist, dass die Middleware selbst keine Datenbankverbindung öffnen sollte. Stattdessen wird ein bereits ausgestelltes, signiertes Token geprüft, etwa mit einer Edge-kompatiblen JWT-Bibliothek wie jose. Die eigentliche Session-Validierung gegen die Datenbank bleibt der Server Component oder dem Route Handler vorbehalten, die Middleware trifft nur die grobe Vorentscheidung: durchlassen oder zur Login-Seite umleiten. Diese Aufgabenteilung hält Next.js Middleware schnell und vermeidet, dass sie zum Flaschenhals wird.

Für Redirects mit erhaltenem Rückkehr-Pfad ist ein Next.js Middleware Pattern besonders verbreitet: Die ursprünglich angeforderte URL wird als Query-Parameter an die Login-Seite angehängt, sodass der Nutzer nach erfolgreicher Anmeldung automatisch zur ursprünglich gewünschten Seite zurückkehrt. Ohne dieses Pattern landen Nutzer nach dem Login immer auf der Startseite, was in der Praxis zu spürbar schlechterer Usability führt.


// middleware.ts — auth guard with return-path preservation
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
import { jwtVerify } from 'jose';

const secret = new TextEncoder().encode(process.env.JWT_SECRET);

export async function middleware(request: NextRequest) {
  const token = request.cookies.get('session')?.value;

  if (!token) {
    return redirectToLogin(request);
  }

  try {
    await jwtVerify(token, secret);
    return NextResponse.next();
  } catch {
    // Token invalid or expired — treat as unauthenticated
    return redirectToLogin(request);
  }
}

function redirectToLogin(request: NextRequest) {
  const loginUrl = new URL('/login', request.url);
  loginUrl.searchParams.set('from', request.nextUrl.pathname);
  return NextResponse.redirect(loginUrl);
}

export const config = {
  matcher: ['/dashboard/:path*', '/settings/:path*'],
};

4. Rewrites und A/B-Testing mit Middleware

Neben Redirects, die dem Browser eine neue URL mitteilen, kann Next.js Middleware auch Rewrites durchführen: Der Nutzer sieht in der Adressleiste weiterhin die ursprüngliche URL, aber intern wird eine andere Seite ausgeliefert. Das ist die technische Grundlage für serverseitiges A/B-Testing ohne Client-seitiges Flackern, weil die Entscheidung getroffen wird, bevor überhaupt HTML gerendert wurde, statt nachträglich per JavaScript die Variante auszutauschen.

Ein typisches Muster liest ein Cookie mit der zugewiesenen Testgruppe, und weist dieses Cookie bei Erstbesuch zufällig zu, damit ein Nutzer über mehrere Sessions hinweg konsistent dieselbe Variante sieht. Next.js Middleware ist der einzige Ort im App Router, an dem diese Entscheidung wirklich vor dem Rendering fällt, denn ein Rewrite in einer Server Component käme zu spät, das Rendering hätte bereits begonnen. Für Marketing-Teams, die Landingpage-Varianten testen, ist dieses Pattern der Unterschied zwischen einem sauberen Test und einem Flicker-Problem im Core Web Vitals Report.


// middleware.ts — server-side A/B test via rewrite, no client flicker
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
  if (request.nextUrl.pathname !== '/landingpage') {
    return NextResponse.next();
  }

  const existingVariant = request.cookies.get('ab-variant')?.value;
  const variant = existingVariant ?? (Math.random() < 0.5 ? 'a' : 'b');

  const response = variant === 'b'
    ? NextResponse.rewrite(new URL('/landingpage/variant-b', request.url))
    : NextResponse.next();

  if (!existingVariant) {
    // Persist assignment for 30 days so returning users stay in the same variant
    response.cookies.set('ab-variant', variant, { maxAge: 60 * 60 * 24 * 30 });
  }

  return response;
}

export const config = {
  matcher: ['/landingpage'],
};

5. Geolocation und Header-basierte Personalisierung

Wenn Next.js auf Vercel oder einer ähnlichen Edge-Plattform läuft, stellt die Runtime der Next.js Middleware geografische Metadaten direkt am Request-Objekt zur Verfügung, ohne dass ein externer Geolocation-Dienst aufgerufen werden muss. Land, Region und Stadt lassen sich damit für Sprachumleitung, Währungsanzeige oder regionale Angebote nutzen, und das mit minimaler Latenz, weil die Information bereits an der Edge vorliegt, statt erst nach einem Roundtrip zu einem Drittanbieter.

Ein verbreitetes Next.js Middleware Pattern leitet Besucher ohne explizite Sprachwahl im Pfad auf Basis von Geolocation und dem Accept-Language-Header auf die passende Sprachversion um, etwa von / auf /de oder /en. Wichtig dabei: Diese Umleitung sollte nur einmalig greifen und danach eine Präferenz-Cookie setzen, damit ein Nutzer, der bewusst eine andere Sprache wählt, nicht bei jedem Seitenaufruf zurückgeleitet wird. Ohne dieses Cookie-Gedächtnis wird die Personalisierung schnell zur Nutzerfalle.


// middleware.ts — locale redirect based on geolocation and Accept-Language
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

const SUPPORTED_LOCALES = ['de', 'en'] as const;

export function middleware(request: NextRequest) {
  const { pathname } = request.nextUrl;
  const hasLocale = SUPPORTED_LOCALES.some((l) => pathname.startsWith(`/${l}`));
  if (hasLocale) return NextResponse.next();

  const preferred = request.cookies.get('preferred-locale')?.value;
  if (preferred) {
    return NextResponse.next();
  }

  const country = request.geo?.country ?? 'US';
  const locale = country === 'DE' || country === 'AT' || country === 'CH' ? 'de' : 'en';

  const url = request.nextUrl.clone();
  url.pathname = `/${locale}${pathname}`;
  const response = NextResponse.redirect(url);
  response.cookies.set('preferred-locale', locale, { maxAge: 60 * 60 * 24 * 365 });
  return response;
}

6. Middleware und Edge Runtime: Einschränkungen verstehen

Next.js Middleware läuft standardmäßig in der Edge Runtime, einer eingeschränkten JavaScript-Umgebung basierend auf Web-Standard-APIs, nicht auf vollem Node.js. Das bedeutet konkret: Kein Dateisystemzugriff, kein natives TCP-Socket, keine Node-spezifischen Module wie fs oder crypto im klassischen Node-API-Stil. Stattdessen stehen Web APIs wie fetch, Request, Response und die Web Crypto API zur Verfügung, die auch im Browser existieren.

Diese Einschränkung ist kein Zufall, sondern Voraussetzung für die geringe Kaltstartzeit, für die die Edge Runtime bekannt ist. Wer versucht, in Next.js Middleware ein klassisches Node-ORM wie Prisma direkt mit einer TCP-Datenbankverbindung zu nutzen, bekommt einen Build- oder Laufzeitfehler, weil die zugrunde liegenden Node-APIs fehlen. Der richtige Weg ist entweder ein Edge-kompatibler Datenbank-Client über HTTP, etwa bei Neon oder PlanetScale, oder das Verschieben der eigentlichen Datenbanklogik in einen Route Handler, der in der Node Runtime läuft.

Seit neueren Next.js-Versionen lässt sich die Runtime für Middleware experimentell auch auf Node umstellen, was mehr Kompatibilität erlaubt, aber die Kaltstart-Vorteile der Edge Runtime aufgibt. Diese Entscheidung, Edge versus Node für Next.js Middleware, hängt direkt mit dem Thema aus Abschnitt drei dieser Artikelreihe zusammen und sollte anhand der tatsächlichen Latenzanforderungen getroffen werden, nicht pauschal.

7. Performance-Overhead und wann Middleware vermeiden

Jede Next.js Middleware-Ausführung fügt dem Request-Pfad zusätzliche Latenz hinzu, selbst wenn die Middleware nur einen einzigen Header liest. Bei global verteilten Edge-Deployments ist dieser Overhead meist im niedrigen einstelligen Millisekundenbereich, kann sich aber summieren, wenn die Middleware synchron auf einen externen Dienst wartet, etwa einen entfernten Feature-Flag-Service ohne lokales Caching. Ein fetch-Aufruf in der Middleware, der nicht zwingend nötig ist, ist der häufigste Performance-Killer in diesem Kontext.

Nicht jede Cross-Cutting-Logik gehört in die Next.js Middleware. Sicherheits-Header, die für jede Route identisch sind, lassen sich oft effizienter über next.config.js setzen, ohne dass überhaupt JavaScript-Code pro Request ausgeführt werden muss. Middleware sollte reserviert bleiben für Entscheidungen, die tatsächlich request-abhängig sind: Auth-Status, A/B-Zuordnung, Geolocation. Alles andere ist statisch konfigurierbar und günstiger als jede noch so schlanke Middleware-Funktion.

8. Fehler und Anti-Patterns bei Next.js Middleware

Der größte Anti-Pattern-Klassiker ist die Middleware, die selbst wieder eine URL erzeugt, die vom eigenen Matcher erneut gematcht wird, was zu einer Redirect-Schleife führt. Das passiert oft bei Sprach-Redirects, wenn die Ziel-URL versehentlich denselben Pfad-Präfix trägt wie die Ausgangs-URL. Ein zweiter verbreiteter Fehler: schwere Berechnungen oder mehrere sequentielle fetch-Aufrufe in einer einzigen Middleware-Instanz, was die eingangs erwähnte Kaltstart- und Latenz-Bilanz der Edge Runtime zunichtemacht.

Ein dritter Fehler betrifft Cookies: Middleware kann Cookies setzen, aber Änderungen an request.cookies wirken sich nicht automatisch auf response.cookies aus, sie müssen explizit auf das Response-Objekt übertragen werden. Wer das übersieht, wundert sich, warum ein in der Middleware gesetztes Cookie im Browser nie ankommt. Ebenfalls verbreitet ist der Versuch, in Next.js Middleware Umgebungsvariablen zu nutzen, die nicht mit dem NEXT_PUBLIC_-Präfix versehen sind, obwohl die Edge Runtime hier eigene Regeln zum Bundling von Server-Variablen hat, die von klassischen Node-Umgebungsvariablen abweichen.

9. Next.js Middleware im Vergleich

Um zu entscheiden, wo eine Logik hingehört, hilft ein direkter Vergleich der verfügbaren Next.js-Mechanismen. Die folgende Tabelle stellt Next.js Middleware den Alternativen Route Handler, Server Component und next.config.js-Konfiguration gegenüber.

Anwendungsfall Ungeeignet Empfohlener Mechanismus Grund
Route-weiter Auth-Schutz Check in jeder page.tsx Next.js Middleware mit Matcher Zentral, läuft vor dem Rendering
Statische Sicherheits-Header In Middleware pro Request setzen next.config.js headers() Kein JS-Overhead pro Request
Datenbankabfrage vor Rendering Direkt in Middleware Route Handler oder Server Component Node Runtime, volle DB-Treiber
A/B-Test ohne Flackern Client-seitiger Redirect Middleware Rewrite Entscheidung vor dem ersten Render
Geolocation-Personalisierung Externer Geo-API-Call im Client request.geo in Middleware Bereits an der Edge verfügbar

Die Tabelle macht deutlich: Next.js Middleware ist kein Ersatz für Route Handler oder Server Components, sondern eine vorgelagerte Entscheidungsschicht mit eigenen, bewusst engen Fähigkeiten. Wer diese Grenze respektiert, bekommt schnelle, wartbare Routing-Logik. Wer sie ignoriert, verschiebt Node-spezifischen Code in eine Umgebung, die dafür nicht gebaut wurde, und riskiert Build-Fehler oder schlechte Latenzwerte.

Mironsoft

Next.js Architektur, Middleware und Edge-Deployments

Middleware, die Auth, Rewrites und Geolocation sauber trennt?

Wir bauen Next.js Middleware Patterns, die Matcher-Regeln präzise eingrenzen, Auth-Redirects korrekt absichern und Edge-Runtime-Grenzen respektieren, ohne Kaltstart-Vorteile zu verschenken.

Middleware-Audit

Matcher-Regeln und Redirect-Ketten auf Schleifen und Overhead prüfen

Auth-Architektur

Edge-kompatible Token-Validierung mit sauberer Trennung zur Session-Datenbank

Edge-Migration

Runtime-Entscheidungen zwischen Edge und Node fundiert treffen

10. Zusammenfassung

Next.js Middleware ist die Schicht, die vor jedem Rendering entscheidet: durchlassen, umleiten oder umschreiben. Mit einer präzisen Matcher-Konfiguration bleibt sie auf genau die Pfade beschränkt, für die sie wirklich gebraucht wird. Auth-Redirects, A/B-Testing-Rewrites und Geolocation-basierte Personalisierung sind die drei Kernanwendungsfälle, die dank der Position der Middleware im Request-Lifecycle ohne Client-seitiges Flackern funktionieren.

Die größte Einschränkung, die Edge Runtime, ist gleichzeitig der Grund für die geringe Latenz von Next.js Middleware. Wer Node-spezifische Bibliotheken oder schwere Datenbankzugriffe in die Middleware verlagert, verletzt dieses Modell und bekommt entweder Build-Fehler oder schlechte Performance. Die saubere Aufgabenteilung, Middleware für schnelle Vorentscheidungen, Route Handler und Server Components für alles andere, ist der Schlüssel zu robusten Next.js Middleware Patterns in Produktion.

Next.js Middleware Patterns: Das Wichtigste auf einen Blick

Matcher-Config

Präzise Pfad-Regeln im config-Export verhindern unnötigen Overhead und Redirect-Schleifen bei jeder Middleware-Ausführung.

Auth vor dem Rendering

Token-Check statt Datenbankzugriff in der Middleware, Redirect mit Rückkehr-Pfad für gute Login-Usability.

Rewrites für A/B-Tests

Serverseitige Variantenwahl per Cookie und Rewrite verhindert Client-seitiges Flackern in Core Web Vitals.

Edge-Grenzen respektieren

Keine Node-APIs, keine schweren DB-Treiber. Edge-kompatible Clients oder Auslagerung in Route Handler nutzen.

11. FAQ: Next.js Middleware Patterns

1Was ist Next.js Middleware genau?
Eine middleware.ts Datei, die vor Routing und Rendering läuft und Requests durchlässt, umleitet oder umschreibt.
2Wofür ist der Matcher da?
Grenzt ein, für welche Pfade die Middleware läuft, verhindert unnötigen Overhead auf statischen Assets.
3Direkter Datenbankzugriff möglich?
Nur über Edge-kompatible HTTP-Clients. Schwere DB-Zugriffe gehören in Route Handler oder Server Components.
4Rewrite vs. Redirect?
Redirect ändert die sichtbare URL, Rewrite liefert intern eine andere Seite ohne sichtbare Änderung.
5Redirect-Schleifen vermeiden?
Ziel-URL darf nicht erneut vom eigenen Matcher erfasst werden, Cookie- oder Präfix-Check nutzen.
6Warum kommt das Cookie nicht an?
Muss explizit auf response.cookies gesetzt werden, request.cookies allein überträgt nichts.
7Immer Edge Runtime?
Standardmäßig ja, Node Runtime experimentell möglich, aber mit längeren Kaltstarts.
8Geolocation nutzen?
request.geo liefert Land, Region und Stadt direkt am Request-Objekt auf unterstützten Edge-Plattformen.
9Sicherheits-Header in Middleware?
Statische Header besser in next.config.js, Middleware für request-abhängige Entscheidungen reservieren.
10Wie lokal testen?
Mit next dev, Header und Cookies über DevTools oder curl simulieren, Funktion mit gemockten Requests unit-testen.