Zum Inhalt springen

Weiterleitungen in Next.js

In Next.js kannst du an vier Stellen weiterleiten: in der Konfiguration, in der Middleware, im Servercode des App Routers und über die Option trailingSlash. Jede davon sendet standardmäßig andere Statuscodes – es lohnt sich also, die Unterschiede zu kennen.

Überblick

MethodeStandard-StatusEinsatzzweck
redirects() in der next.config.js308 (permanent: true) oder 307Feste, bekannte URL-Zuordnungen
Middleware / Proxy mit NextResponse.redirect()307Bedingungen zur Laufzeit: Cookies, Standort, große Redirect-Listen
redirect() im App Router307 (303 in Server Actions)Weiterleitung nach Logik in Server Components, Route Handlern, Server Actions
permanentRedirect()308Dauerhaft umgezogene Inhalte, im Servercode entschieden
trailingSlash308URLs mit oder ohne Slash am Ende vereinheitlichen

Next.js setzt lieber auf 307 und 308 als auf 302 und 301, weil diese Codes die Anfragemethode garantiert beibehalten: Aus einem POST wird kein GET. Für Suchmaschinen ist 308 gleichwertig zu 301 und 307 zu 302. Die Hintergründe erklärt 307 vs. 308.

redirects() in der next.config.js

Die Funktion redirects in deiner Konfiguration gibt ein Array von Regeln zurück. Next.js prüft sie noch vor dem Dateisystem – sie greifen also auch für URLs, zu denen es keine Seite mehr gibt:

/** @type {import('next').NextConfig} */
const nextConfig = {
  async redirects() {
    return [
      // 308 Permanent Redirect
      {
        source: '/ueber-uns',
        destination: '/about',
        permanent: true,
      },
      // Pfadparameter
      {
        source: '/blog/:slug',
        destination: '/news/:slug',
        permanent: true,
      },
      // Wildcard: passt auch auf /docs/a/b/c
      {
        source: '/docs/:path*',
        destination: 'https://docs.example.com/:path*',
        permanent: false,
      },
      // Expliziter Statuscode statt permanent
      {
        source: '/alter-shop',
        destination: '/shop',
        statusCode: 301,
      },
    ]
  },
}

module.exports = nextConfig

Ein paar Regeln solltest du dir merken:

  • permanent: true sendet 308, permanent: false sendet 307. Brauchst du für einen alten Client einen klassischen 301, nimm statusCode statt permanent – nicht beides.
  • Query-Strings werden automatisch ans Ziel weitergereicht.
  • Mit has und missing prüfst du Header, Cookies, Query-Parameter oder den Host. So leitest du zum Beispiel innerhalb von Next.js von www auf die Domain ohne www um:
{
  source: '/:path*',
  has: [{ type: 'host', value: 'www.example.com' }],
  destination: 'https://example.com/:path*',
  permanent: true,
}

Hostest du bei Vercel, ist dafür eine Domain-Weiterleitung im Dashboard einfacher, siehe Weiterleitungen bei Vercel und Netlify. Mit next.config.ts bleibt die Syntax gleich, du exportierst nur per export default nextConfig. Wichtig: Mit output: 'export' funktioniert redirects() nicht, denn bei einem statischen Export gibt es keinen Server, der einen Statuscode senden könnte.

Middleware: NextResponse.redirect()

Die Middleware läuft, bevor eine Route gerendert wird, und kann für jede Anfrage einzeln entscheiden. Seit Next.js 16 heißt die Datei proxy.ts und die exportierte Funktion proxy; in älteren Versionen ist es middleware.ts mit der Funktion middleware. Die API ist dieselbe:

// proxy.ts (Next.js 16) bzw. middleware.ts (Next.js 15 und älter)
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function proxy(request: NextRequest) {
  if (!request.cookies.has('session')) {
    // standardmäßig 307
    return NextResponse.redirect(new URL('/login', request.url))
  }

  if (request.nextUrl.pathname === '/alte-preise') {
    // ausdrücklich dauerhaft
    return NextResponse.redirect(new URL('/preise', request.url), 308)
  }

  return NextResponse.next()
}

export const config = {
  matcher: ['/dashboard/:path*', '/alte-preise'],
}

NextResponse.redirect() erwartet eine absolute URL, deshalb baut das Beispiel sie mit new URL(pfad, request.url) zusammen. Schränk die Middleware per matcher ein, damit sie nicht bei jedem Bild und jeder statischen Datei anspringt.

Die Middleware ist auch der empfohlene Ort für große Redirect-Listen mit Tausenden Einträgen: Du lädst eine Zuordnung aus einer JSON-Datei oder einem Edge-Speicher, schlägst den Pfad nach und leitest bei einem Treffer weiter. Für riesige Listen ist die Konfigurationsdatei nicht gedacht.

redirect() und permanentRedirect() im App Router

In Server Components, Route Handlern und Server Actions importierst du die Funktionen aus next/navigation:

// app/produkte/[id]/page.tsx
import { redirect, permanentRedirect, notFound } from 'next/navigation'

export default async function Page({ params }: { params: Promise<{ id: string }> }) {
  const { id } = await params
  const product = await getProduct(id)

  if (!product) {
    notFound()
  }

  if (product.slug !== id) {
    // dauerhaft umgezogen: 308
    permanentRedirect(`/produkte/${product.slug}`)
  }

  if (!product.published) {
    // vorübergehend: 307
    redirect('/produkte')
  }

  return <h1>{product.name}</h1>
}
  • redirect() sendet 307; in einer Server Action dagegen 303 See Other, damit der Browser anschließend per GET lädt.
  • permanentRedirect() sendet 308.
  • Beide werfen intern einen Fehler, ein return brauchst du also nicht. Ruf sie aber nicht innerhalb eines try-Blocks auf, sonst verschluckt dein catch die Weiterleitung.
  • Wird die Antwort bereits gestreamt, lässt sich der Statuscode nicht mehr ändern. Next.js fügt dann ein Meta-Tag ein, das im Browser weiterleitet. Crawler behandeln das anders als einen echten HTTP-Redirect – löse Weiterleitungen daher aus, bevor eine Suspense-Grenze zu streamen beginnt. Ob du einen 308 oder einen Meta Refresh bekommst, zeigt dir der Redirect-Checker.

Im Pages Router gibst du stattdessen aus getServerSideProps oder getStaticProps das Objekt { redirect: { destination: '/login', permanent: false } } zurück.

trailingSlash

Standardmäßig leitet Next.js /about/ per 308 auf /about um. Mit trailingSlash: true passiert das Gegenteil:

module.exports = {
  trailingSlash: true, // /about -> /about/ (308)
}

Entscheide dich für eine Schreibweise und halte deine internen Links daran – sonst kostet jeder interne Link einen zusätzlichen Sprung. Zeigt eine Regel in redirects() auf die „falsche“ Schreibweise, kommt der Slash-Redirect noch obendrauf und du hast eine Redirect-Kette. Mit skipTrailingSlashRedirect: true schaltest du die automatische Weiterleitung ab und regelst das selbst in der Middleware.

Redirects vs. Rewrites

Beide nutzen dieselbe Syntax mit source und destination, machen aber etwas grundlegend anderes:

RedirectRewrite
URL im BrowserWechselt zum ZielBleibt unverändert
HTTP-Antwort3xx mit Location-Header200 mit dem Inhalt des Ziels
SuchmaschinenIndexieren das ZielIndexieren die ursprüngliche URL
Typischer EinsatzUmgezogene Inhalte, DomainwechselAPI durchreichen, saubere URLs, Multi-Zone-Apps
async rewrites() {
  return [
    { source: '/api/:path*', destination: 'https://api.example.com/:path*' },
  ]
}

Ist eine URL wirklich umgezogen, nimm einen Redirect. Ein Rewrite ließe die alte URL im Index und lieferte denselben Inhalt unter zwei Adressen aus.

Reihenfolge der Auswertung

Next.js arbeitet eine Anfrage in dieser Reihenfolge ab: headers, redirects, Middleware/Proxy, beforeFiles-Rewrites, Routen aus dem Dateisystem, afterFiles-Rewrites, dynamische Routen, fallback-Rewrites. Eine Regel in redirects() gewinnt also gegen eine Seite mit demselben Pfad und gegen deine Middleware.

Testen

next dev verhält sich nicht immer wie die Produktion, vor allem nicht hinter einem CDN. Schick nach dem Deployment die wichtigsten URLs durch den Redirect-Checker und prüf den Statuscode jedes Sprungs. Für viele URLs auf einmal gibt es den Bulk-Checker. Mehr zu den Statuscodes, die Next.js sendet, findest du unter 301 vs. 302.

Häufige Fragen

Warum sendet Next.js 308 statt 301?

308 ist die dauerhafte Weiterleitung, bei der die Anfragemethode erhalten bleibt. Nach einem 301 dürfen Browser aus einem POST ein GET machen. Google behandelt 308 wie 301. Brauchst du trotzdem einen 301, setz statusCode: 301 statt permanent.

Was ist der Unterschied zwischen redirect() und permanentRedirect()?

redirect() sendet einen vorübergehenden 307 (in Server Actions 303), permanentRedirect() einen dauerhaften 308. Nimm die dauerhafte Variante nur, wenn die alte URL aus den Suchergebnissen verschwinden soll.

Warum funktioniert redirect() in try/catch nicht?

redirect() wirft einen speziellen Fehler, den Next.js abfängt. Ein umschließendes catch fängt ihn vorher ab. Ruf redirect() nach dem try/catch-Block auf oder wirf den Fehler erneut.

Funktionieren Redirects aus der next.config.js beim statischen Export?

Nein. Mit output: 'export' gibt es keinen Next.js-Server, der Statuscodes senden könnte. Richte die Weiterleitungen dann bei deinem Hoster ein, etwa in der vercel.json, in Netlifys _redirects, per .htaccess oder in nginx.

  • .htaccess-Weiterleitung auf Apache

    So leitest du einzelne Seiten und ganze Domains per .htaccess weiter: mod_alias oder mod_rewrite, fertige Regeln für die typischen Fälle und wie du Schleifen und Ketten vermeidest.

  • Weiterleitungen mit nginx

    Fertige nginx-Konfiguration für 301-Weiterleitungen: einzelne Seiten, Muster, ganze Domains, HTTPS und www in einem Hop und Hunderte URLs per map.

  • Weiterleitungen mit Cloudflare

    Cloudflare kann Weiterleitungen direkt am Edge beantworten, bevor eine Anfrage deinen Server erreicht. So funktionieren Single Redirects, Bulk Redirects und Always Use HTTPS – und so verhinderst du, dass sie sich mit deinem Server in die Quere kommen.

  • Weiterleitungen in WordPress

    In WordPress kannst du URLs auf mehreren Wegen weiterleiten: per Plugin, per Regel in der .htaccess oder mit ein paar Zeilen PHP. Hier erfährst du, welcher Weg wann passt und wie du die typischen Stolperfallen mit Caching und HTTPS umgehst.

  • Weiterleitungen bei Vercel und Netlify

    Bei Vercel und Netlify fasst du keine Webserver-Konfiguration an. Weiterleitungen stehen in einer Datei in deinem Repository oder im Dashboard, und das Edge-Netzwerk der Plattform liefert sie aus. So funktionieren beide – und hier unterscheiden sie sich.

  • Weiterleitungen mit Microsoft IIS

    IIS bietet dir zwei Wege für Weiterleitungen: die eingebaute HTTP-Umleitung und das URL-Rewrite-Modul. Hier erfährst du, wann du welches nimmst – mit web.config-Beispielen zum Kopieren.