Hirefullstack – Software Engineering & IT-Beratung aus Berlin
← Zur Übersicht
Einstieg 12 Min Lesezeit

Routing über Ordner

Adressen entstehen aus dem Dateibaum – mit ein paar Sonderzeichen

In einem Satz

Jeder Ordner in app/ ist ein Stück der Adresse, jede page.tsx macht sie aufrufbar. Klammern um Ordnernamen ändern, was das Segment bedeutet.

Es gibt keine Routen-Datei, die du pflegen musst. Wo eine Seite liegt, das ist ihre Adresse. Diese Lektion zeigt die vier Klammer-Schreibweisen, mit denen du davon abweichst.

Der Normalfall

app/
app/
  page.tsx/
  kontakt/
    page.tsx/kontakt
  blog/
    page.tsx/blog
    [slug]/
      page.tsx/blog/beliebiger-wert

[slug] ist ein Dynamisches SegmentEin Ordner in eckigen Klammern, `[slug]`, der für jeden beliebigen Wert an dieser Stelle steht.`[...alles]` fängt beliebig viele Stufen ab, `[[...alles]]` zusätzlich auch den leeren Fall.: Der Ordnername in eckigen Klammern steht für einen beliebigen Wert. Was tatsächlich in der Adresse stand, bekommt die Seite als Parameter.

app/blog/[slug]/page.tsx
export default async function Page({
  params,
}: {
  params: Promise<{ slug: string }>;
}) {
  const { slug } = await params;
  const artikel = await ladeArtikel(slug);

  return <h1>{artikel.titel}</h1>;
}
Seit Next.js 15 ist params ein Promise – du musst es awaiten, bevor du hineinschaust.
Stolperstein params und searchParams sind Promises

Ältere Beispiele im Netz greifen direkt mit params.slug zu. Seit Version 15 ergibt das undefined bzw. eine Warnung. Immer erst const { slug } = await params;.

Die vier Klammern

klammern.txt
[slug]        ein Wert          /blog/hallo
[...pfad]     beliebig viele    /docs/a/b/c
[[...pfad]]   auch gar keiner   /docs  und  /docs/a/b
(gruppe)      taucht NICHT in der Adresse auf

Die Route-GruppeEin Ordner in runden Klammern, `(marketing)`, der nur zum Sortieren dient und nicht in der Adresse auftaucht. in runden Klammern ist reine Ordnung: app/(marketing)/preise/page.tsx liegt unter /preise, nicht unter /marketing/preise. Praktisch, um Bereichen ein eigenes Layout zu geben, ohne die Adressen zu verändern.

gruppen.txt
app/
  (marketing)/
    layout.tsx             ← Layout nur für diesen Bereich
    page.tsx               →  /
    preise/page.tsx        →  /preise
  (app)/
    layout.tsx             ← ein anderes Layout
    dashboard/page.tsx     →  /dashboard

Navigieren

navigation.tsx
import Link from "next/link";

<Link href="/blog">Zum Blog</Link>
<Link href={`/blog/${artikel.slug}`}>{artikel.titel}</Link>

// Programmgesteuert – nur in Client-Komponenten:
"use client";
import { useRouter } from "next/navigation";

const router = useRouter();
router.push("/danke");
Tipp Immer next/link statt <a>

next/linkInterner Verweis, der die Zielseite im Hintergrund vorlädt, sobald der Verweis sichtbar wird. lädt die Zielseite im Hintergrund vor, sobald der Verweis sichtbar wird, und wechselt ohne kompletten Seitenneuaufbau. Ein normales <a href> wirft die ganze Anwendung weg und lädt neu.

Achtung next/navigation, nicht next/router

useRouter gibt es zweimal. Im App Router kommt es aus next/navigation. Der Import aus next/router gehört zum alten Pages Router und wirft zur Laufzeit einen Fehler.

Was noch in einen Ordner darf

ordner.txt
app/blog/
  page.tsx          die Seite
  layout.tsx        Rahmen für /blog und alles darunter
  loading.tsx       Anzeige, solange geladen wird
  error.tsx         Auffangnetz
  BlogKarte.tsx     ganz normale Komponente, erzeugt KEINE Adresse
  utils.ts          Hilfsfunktionen, ebenfalls harmlos

Nur die reservierten Namen haben eine Bedeutung. Alles andere kannst du dort ablegen, wo es gebraucht wird – Komponenten müssen nicht in einen zentralen components/-Ordner wandern.

Genauer erklärt: statische Adressen aus dynamischen Segmenten optional

Eine Seite mit [slug] wird standardmäßig bei jeder Anfrage neu erzeugt – Next.js weiß ja nicht, welche Werte es gibt. Mit generateStaticParamsSagt Next.js beim Bauen, welche konkreten Werte ein dynamisches Segment annehmen soll – damit daraus statische Seiten werden. sagst du es ihm, und aus der dynamischen Seite werden echte statische Dateien.

app/blog/[slug]/page.tsx
export async function generateStaticParams() {
  const artikel = await ladeAlleArtikel();
  return artikel.map((a) => ({ slug: a.slug }));
}

// Ergebnis: beim Bauen entsteht je Artikel eine fertige Seite.
Gut zu wissen Was mit unbekannten Werten passiert

Ruft jemand einen Slug auf, der nicht in der Liste stand, erzeugt Next.js die Seite bei Bedarf und merkt sie sich. Willst du das nicht, setzt du export const dynamicParams = false – dann gibt es für alles andere eine 404.

Sitzt das schon?

5 Fragen zu dieser Lektion. Falsche Antworten landen in deiner Statistik.

Hirefullstack

Ihr braucht React-Verstärkung im Team?

Wir bauen seit Jahren React- und Next.js-Anwendungen für Kunden in ganz Deutschland – als einzelner Experte, als Verstärkung fürs Bestandsteam oder als komplettes Scrum-Team.

Projekt besprechen →