8.1 Next.js: Projekt, Routing und Layouts
Nach dieser Einheit kannst du:
- den Unterschied zwischen Bibliothek und Framework erklären und nennen, was Next.js gegenüber reinem React übernimmt.
- ein Next.js-Projekt mit TypeScript und App Router anlegen, starten und seine Struktur erklären.
- Seiten über die Ordnerstruktur anlegen und dynamische Segmente wie
[id]auslesen. - gemeinsame Rahmen als verschachtelte Layouts umsetzen und mit
Linknavigieren.
Wer ein Regal braucht, kauft Bretter und Schrauben und baut, wie er will: Die Werkzeuge warten, bis man sie in die Hand nimmt. Wer ein Fertighaus bestellt, bekommt einen Plan mit Wänden, Leitungen und Stiegenhaus; man entscheidet über Fenster, Farben und Möbel, aber nicht mehr, wo das Stiegenhaus hinkommt. React aus Kapitel 7 ist das Werkzeug: Unser Code ruft es auf. Next.js ist das Fertighaus: Es gibt die Struktur vor und ruft unseren Code an den vorgesehenen Stellen auf.
flowchart LR
accTitle: Bibliothek und Framework im Vergleich
subgraph lib["Bibliothek: React"]
direction TB
own1["dein Code"] -- "ruft auf" --> react["React"]
end
subgraph fw["Framework: Next.js"]
direction TB
next["Next.js"] -- "ruft auf" --> own2["dein Code in<br/>app/.../page.tsx"]
end
Abb. 8.1: Eine Bibliothek wird von deinem Code aufgerufen, ein Framework ruft deinen Code auf (eigene Darstellung).
Diese Umkehrung der Kontrolle ist das Wesen jedes Frameworks; sie erklärt, warum ein Framework Konventionen hat, die man lernt, statt sie zu diskutieren. Der Lehrplan verlangt die Entwicklung von Anwendungen “unter Verwendung von Frameworks und Middleware”, und unser Framework ist Next.js: der verbreitete Rahmen um React, der Client und Server in einem Projekt vereint. Er bringt mit, was React fehlt: mehrere Seiten mit URLs, einen Server, der sie ausliefert, einen fertig eingerichteten Build und später einen Ort für die eigene API.
Damit endet die Vite-Phase aus Kapitel 7. Deine Komponenten wandern unverändert mit: JSX, Props, State und Hooks bleiben dieselben. Neu sind die Ordnerstruktur, das Routing und die Frage, ob eine Komponente am Server oder im Browser läuft; die klärt Einheit 8.2.
Begriffe vorab
Abschnitt betitelt „Begriffe vorab“- Framework: ein Rahmen, der die Struktur einer Anwendung vorgibt und deinen Code an festgelegten Stellen aufruft.
- Route: eine aufrufbare Adresse der Anwendung, etwa
/jobs. - Segment: ein Teil des Pfads zwischen zwei Schrägstrichen;
/jobs/42hat die Segmentejobsund42. - Dynamisches Segment: ein Platzhalter im Pfad, im Ordnernamen in eckigen Klammern, etwa
[id]. - Layout: ein Rahmen, der alle Seiten eines Ordners und seiner Unterordner umschließt.
Projekt anlegen
Abschnitt betitelt „Projekt anlegen“-
Projekt erzeugen. Der Assistent
create-next-appfragt sonst eine Reihe von Einstellungen ab; im Kurs geben wir sie gleich als Optionen mit, damit alle dasselbe Projekt bekommen:Terminal-Fenster npx create-next-app@latest render-farm --ts --app --biome --no-tailwind --no-src-dir --no-react-compiler --cache-components --import-alias "@/*" --use-npm --yes -
Entwicklungsserver starten:
Terminal-Fenster cd render-farmnpm run devDie Anwendung läuft auf
http://localhost:3000und aktualisiert sich bei jeder gespeicherten Änderung selbst. -
Struktur ansehen. Die wichtigsten Bestandteile:
render-farm/├── app/ # pages, layouts, later API routes│ ├── layout.tsx # root layout (html, body, navigation)│ └── page.tsx # the start page /├── public/ # static files (images, favicon)├── package.json # scripts and dependencies├── next.config.ts # framework configuration, cacheComponents: true├── biome.json # linter and formatter, as in chapter 1└── tsconfig.json # TypeScript, preconfigured strict
Beispielprojekt: 08_nextjs_struktur_routing_examples/ex01_app_router
Die Optionen im Überblick:
| Option | Bedeutung |
|---|---|
--ts, --app | TypeScript und der App Router (Ordner app/) |
--biome | Biome als Linter und Formatierer, wie seit Kapitel 1 |
--no-tailwind, --no-src-dir | kein Tailwind, der Ordner app/ liegt direkt im Projekt |
--no-react-compiler | eine automatische Optimierung, die der Kurs nicht verwendet |
--cache-components | Cache Components: Next.js rendert jede Seite beim Build vor und verlangt, dass du Daten ausdrücklich zwischenspeicherst oder pro Anfrage lädst (Einheit 8.2) |
--import-alias "@/*", --use-npm, --yes | Importe ab Projektwurzel mit @/, npm als Paketverwaltung, alle übrigen Fragen mit dem Standardwert |
Bemerkenswert ist, was fehlt: kein Bundler-Setup, keine tsc-Aufrufe, kein Server-Skript. Das Framework übernimmt Build, TypeScript und Serverbetrieb; npm run dev für die Entwicklung, npm run build und npm start für den Produktionsbetrieb. Beim ersten npm run dev legt Next.js zusätzlich eine Datei AGENTS.md mit Hinweisen für KI-Assistenten an; sie darf bleiben.
App Router: Ordner sind Routen
Abschnitt betitelt „App Router: Ordner sind Routen“Next.js leitet die URLs der Anwendung aus der Ordnerstruktur unter app/ ab. Ein Ordner ist ein URL-Segment, die Datei page.tsx darin macht das Segment zur aufrufbaren Seite:
app/├── page.tsx -> /├── jobs/│ ├── page.tsx -> /jobs│ └── [id]/│ └── page.tsx -> /jobs/42, /jobs/7, ...└── presets/ └── page.tsx -> /presetsflowchart LR
accTitle: Ordner unter app werden zu Routen
app["app/"] --> p0["page.tsx<br/>/"]
app --> jobs["jobs/"]
jobs --> p1["page.tsx<br/>/jobs"]
jobs --> id["[id]/"]
id --> p2["page.tsx<br/>/jobs/42"]
app --> presets["presets/"]
presets --> p3["page.tsx<br/>/presets"]
Abb. 8.2: Ein Ordner ist ein Segment, erst page.tsx macht daraus eine Seite (eigene Darstellung).
Eine Seite ist eine gewöhnliche React-Komponente als Standardexport:
export default function JobsPage() { return <h1>Render jobs</h1>;}Dynamische Segmente stehen in eckigen Klammern: Der Ordner [id] fängt jeden Wert an dieser Stelle, und die Seite erhält ihn über die Prop params. In aktuellen Next.js-Versionen ist params ein Promise, daher async und await:
export default async function JobDetailPage({ params,}: { params: Promise<{ id: string }>;}) { const { id } = await params; return <h1>Job {id}</h1>;}Die ID steht erst fest, wenn jemand die Seite aufruft. Next.js rendert mit Cache Components aber jede Seite schon beim Build vor (Einheit 8.2) und braucht für den Teil, der noch fehlt, einen Platzhalter. Den liefert eine Datei loading.tsx im selben Ordner; ohne sie bricht npm run build mit der Meldung “Next.js encountered uncached or runtime data during prerendering” ab.
// app/jobs/[id]/loading.tsx: shown until the id is knownexport default function Loading() { return <p>Loading job ...</p>;}Beispielprojekt: 08_nextjs_struktur_routing_examples/ex01_app_router
Damit lässt sich das URL-Schema aus Kapitel 6 direkt abbilden: Sammlung unter /jobs, Element unter /jobs/42. Der Wert in id ist immer ein String, auch wenn er wie eine Zahl aussieht. Für unbekannte Pfade liefert Next.js automatisch eine 404-Seite; eine eigene Datei app/not-found.tsx gestaltet sie, und die Funktion notFound() aus next/navigation löst sie aus, etwa wenn es den Job mit dieser ID nicht gibt. Genauer erklärt: Weil der Platzhalter aus loading.tsx dann schon unterwegs ist, antwortet der Server mit Status 200 statt 404; Next.js markiert die Seite dafür mit noindex, damit Suchmaschinen sie nicht aufnehmen.
Wo begegnet dir das? In fast jeder Adresszeile: Ein Online-Shop zeigt Produkte unter Adressen wie /produkte/12345. Es gibt nicht hunderttausend Seiten-Dateien, sondern eine einzige für /produkte/[id], die jedes Produkt anzeigt.
Auflösung
(a) app/about/page.tsx. (b) app/presets/[name]/page.tsx, der Name kommt in params. (c) app/jobs/[id]/log/page.tsx: ein normales Segment unter dem dynamischen. (d) app/not-found.tsx.
Layouts: der gemeinsame Rahmen
Abschnitt betitelt „Layouts: der gemeinsame Rahmen“Eine Datei layout.tsx umschließt alle Seiten ihres Ordners und aller Unterordner. Das Wurzel-Layout trägt das HTML-Gerüst und die Navigation, die auf jeder Seite erscheint:
import Link from "next/link";
export default function RootLayout({ children }: { children: React.ReactNode }) { return ( <html lang="de"> <body> <nav> <Link href="/">Start</Link> <Link href="/jobs">Jobs</Link> <Link href="/presets">Presets</Link> </nav> <main>{children}</main> </body> </html> );}children ist die jeweils aktive Seite; das Layout selbst bleibt beim Seitenwechsel erhalten, samt seinem Zustand, etwa einem geöffneten Menü. Layouts verschachteln sich: Ein zusätzliches app/jobs/layout.tsx umschließt nur die Jobs-Seiten, innerhalb des Wurzel-Layouts.
// app/jobs/layout.tsx: wraps only the job pages, inside the root layoutexport default function JobsLayout({ children }: { children: React.ReactNode }) { return ( <section> <p>Job area</p> {children} </section> );}flowchart TD
accTitle: Verschachtelte Layouts um eine Seite
root["app/layout.tsx<br/>html, body, Navigation"] --> jl["app/jobs/layout.tsx<br/>Job area"]
jl --> page["app/jobs/[id]/page.tsx<br/>Job 42"]
root --> pp["app/presets/page.tsx<br/>ohne Job-Rahmen"]
Abb. 8.3: Das Wurzel-Layout umschließt alles, das Bereichs-Layout nur die Seiten unter jobs/ (eigene Darstellung).
Navigiert wird mit der Komponente Link statt <a>:
sequenceDiagram
accTitle: Seitenwechsel mit a und mit Link
participant b as Browser
participant s as Server
Note over b: a href=/jobs
b->>s: ganze Seite /jobs anfordern
s-->>b: komplettes HTML, alles neu, Zustand weg
Note over b: Link href=/jobs
b->>s: nur Inhalt für /jobs
s-->>b: neue Seite für children, Layout bleibt
Abb. 8.4: Mit <a> lädt der Browser alles neu, mit Link tauscht Next.js nur den Inhalt (eigene Darstellung).
Dieses Wurzel-Layout mit Navigation ist ab jetzt das gemeinsame Gerüst, in dem alle weiteren Übungen dieses Jahres wohnen.
Auflösung
Mit <a> ist der Text weg: Der Browser lädt die ganze Seite neu, auch das Layout, und jeder Zustand im Speicher geht verloren. Mit Link bleibt “intro” stehen: Nur der Inhaltsbereich (children) wird ausgetauscht, das Layout mit dem Suchfeld bleibt, wie es ist.
Stolperfallen
Abschnitt betitelt „Stolperfallen“- Datei heißt nicht
page.tsx:app/jobs/jobs.tsxerzeugt keine Route; nurpage.tsxmacht einen Ordner aufrufbar. paramsohneawait: In aktuellen Versionen istparamsein Promise; beiparams.idmeldet TypeScriptTS2339: Property 'id' does not exist on type 'Promise<{ id: string; }>'.loading.tsxfehlt bei[id]:npm run buildbricht ab, weil die Seite ohne Platzhalter nicht vorgerendert werden kann.idals Zahl behandelt: Werte aus dem Pfad sind Strings;id === 42ist immer falsch.<a>für interne Ziele: Jeder Klick lädt die ganze Seite neu, Layout-Zustand geht verloren.- Assistent ohne Optionen: Mit den Standardwerten entsteht ein Projekt mit Tailwind und anderen Einstellungen als in den Beispielen des Kurses.
Zusatzmaterialien
Abschnitt betitelt „Zusatzmaterialien“- Next.js: Installation - Projekt anlegen, Systemvoraussetzungen, Projektstruktur.
- Next.js: Layouts and Pages - Seiten, Layouts, dynamische Segmente und Links im Überblick.
- Next.js: create-next-app - alle Optionen des Assistenten.
- Next.js: Link-Komponente - Vorladen, aktiver Link und weitere Props.
Zum Anhören
Abschnitt betitelt „Zum Anhören“Du kannst dir diese Einheit kostenlos mit der Vorlesefunktion deines Browsers oder Betriebssystems vorlesen lassen (etwa „Laut vorlesen” in Edge), ohne Konto und ohne Upload; die Codebeispiele und Ordnerbäume liest du dabei am Bildschirm mit. Freiwillig kannst du mit Google NotebookLM (Google-Konto nötig) aus diesem öffentlichen Text eine gesprochene Zusammenfassung erzeugen, auch auf Deutsch.
Lernergebnisse
Abschnitt betitelt „Lernergebnisse“Du kannst jetzt:
- den Unterschied zwischen Bibliothek und Framework erklären und nennen, was Next.js gegenüber reinem React übernimmt.
- ein Next.js-Projekt mit TypeScript und App Router anlegen, starten und seine Struktur erklären.
- Seiten über die Ordnerstruktur anlegen und dynamische Segmente wie
[id]auslesen. - gemeinsame Rahmen als verschachtelte Layouts umsetzen und mit
Linknavigieren.
Passende Übungen
Abschnitt betitelt „Passende Übungen“- Aufgabe 08-1a - Mehrseiter mit Next.js, Stufe Wesentlich_überwiegend
Quellen
Abschnitt betitelt „Quellen“- Projektanlage, Optionen des Assistenten → Next.js: create-next-app; Projektinhalt, Turbopack im Build,
AGENTS.mdbeim erstennpm run dev→ eigener Test mitcreate-next-appund Next.js 16.4.0 (Oktober 2026) - Seiten, Layouts, dynamische Segmente,
paramsals Promise → Next.js: Layouts and Pages, Dynamic Route Segments;notFound()→ Next.js: notFound - Meldung TS2339 bei
params.idohneawait, Build-Abbruch ohneloading.tsx→ eigener Test mit Next.js 16.4.0 und Cache Components (Oktober 2026) loading.tsxals Platzhalter → Next.js: loading.js; Status 200 undnoindexbeinotFound()nach Beginn des Streamings → Next.js: notFound und eigener TestLink, Vorladen,usePathname→ Next.js: Link-Komponente- Turbopack → Next.js: Turbopack
- Lehrplanbezug (Frameworks und Middleware) → Lehrplan der Höheren Lehranstalt für Informationstechnologie, B.2 Medientechnik, 2.1 Softwareentwicklung, IV. Jahrgang (zitiert auf der Kursseite Lehrplan und Ablauf)
- Abb. 8.1 (Bibliothek und Framework), Abb. 8.2 (Ordner und Routen), Abb. 8.3 (verschachtelte Layouts), Abb. 8.4 (
aundLink) → eigene Darstellung, alle als Mermaid-Diagramm
Autoren
Abschnitt betitelt „Autoren“- Oliver Maurhart (MAO)
- Michael Gabriel (GAM)
CC-BY-SA