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

Statisch oder dynamisch

Wann eine Seite beim Bauen entsteht – und wann bei jedem Aufruf

In einem Satz

Next.js entscheidet selbst, ob eine Seite statisch oder dynamisch ist – anhand dessen, was du benutzt. Wer das weiß, steuert es absichtlich statt zufällig.

Es gibt keinen Schalter „diese Seite bitte statisch“. Next.js schaut sich an, was deine Seite braucht, und leitet daraus ab, wann sie erzeugt werden kann. Diese Lektion macht die Ableitung sichtbar.

Die drei Möglichkeiten

moeglichkeiten.txt
Statisch          einmal beim Bauen erzeugt, für alle gleich
                  → schnellstmöglich, kostet fast nichts
                  Startseite, Blogartikel, Dokumentation

Statisch + Zeit   wie oben, aber mit Verfallsdatum (revalidate)
                  → aktuell genug, ohne pro Aufruf zu arbeiten
                  Preisliste, Nachrichtenübersicht

Dynamisch         bei jeder Anfrage neu erzeugt
                  → nötig, sobald es persönlich wird
                  Konto, Warenkorb, Dashboard
Bildlich gesprochen

Statisch ist ein gedrucktes Plakat: einmal produziert, tausendfach aufgehängt. Dynamisch ist ein handgeschriebener Zettel pro Person. Und revalidate ist das Plakat, das jeden Morgen neu gedruckt wird.

Woran Next.js es festmacht

ableitung.txt
Statisch bleibt die Seite, solange nichts davon vorkommt:

  cookies()          → braucht die konkrete Anfrage
  headers()          → dito
  searchParams       → dito
  no-store beim fetch
  export const dynamic = "force-dynamic"

Fehlt all das, kann Next.js die Seite beim Bauen fertigstellen.
Tipp Die Bauausgabe verrät alles

npm run build listet jede Adresse mit einem Symbol: statisch, ƒ dynamisch, beim Bauen aus generateStaticParams erzeugt. Wenn dort etwas anderes steht als erwartet, hast du die Ursache gefunden, bevor du eine Zeile Code liest.

Dynamische Adressen statisch machen

Eine Seite mit [slug] ist zunächst dynamisch – Next.js kennt die möglichen Werte ja nicht. Mit generateStaticParamsSagt Next.js beim Bauen, welche konkreten Werte ein dynamisches Segment annehmen soll – damit daraus statische Seiten werden. nennst du sie, und aus einer Adresse werden viele fertige Seiten.

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

export default async function Seite({
  params,
}: {
  params: Promise<{ slug: string }>;
}) {
  const { slug } = await params;
  const artikel = await ladeArtikel(slug);
  return <article>{artikel.inhalt}</article>;
}
Beim Bauen entsteht je Artikel eine fertige Datei – so schnell wie eine Startseite.
Gut zu wissen Was mit unbekannten Werten passiert

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

Der häufigste Fehler

Persönliches in einer sonst statischen Seite
die ganze Seite wird dynamisch
export default async function Startseite() {
  const nutzer = await ausCookieLesen();   // macht ALLES dynamisch
  const artikel = await ladeArtikel();

  return (
    <>
      <Begruessung nutzer={nutzer} />
      <ArtikelListe artikel={artikel} />
    </>
  );
}
nur der persönliche Teil
export default async function Startseite() {
  const artikel = await ladeArtikel();     // bleibt statisch

  return (
    <>
      <Suspense fallback={<BegruessungSkelett />}>
        <Begruessung />                    {/* liest das Cookie selbst */}
      </Suspense>
      <ArtikelListe artikel={artikel} />
    </>
  );
}

Die dynamische Abhängigkeit steckt jetzt in einer eigenen Komponente hinter <Suspense>. Der Rest der Seite kann weiterhin beim Bauen entstehen.

Bewusst steuern

steuerung.tsx
// in page.tsx oder layout.tsx – gilt für alles darunter

export const dynamic = "force-dynamic";   // immer frisch
export const dynamic = "force-static";    // immer statisch (Fehler bei cookies())
export const revalidate = 3600;           // statisch mit Verfallsdatum
Achtung force-dynamic ist selten die richtige Antwort

Es ist verlockend, wenn etwas nicht aktuell wird. Aber damit verzichtest du auf den größten Vorteil des Frameworks. Erst prüfen, ob nicht revalidate oder ein gezieltes revalidateTag genügt.

Genauer erklärt: was beim Bauen wirklich passiert optional
build-ausgabe.txt
Route (app)                        Size     First Load JS
┌ ○ /                               1.2 kB          92 kB
├ ● /blog/[slug]                    850 B           91 kB
│   ├ /blog/hallo-welt
│   └ /blog/next-15
├ ƒ /konto                          2.1 kB          95 kB
└ ○ /impressum                      180 B           88 kB

○  statisch      beim Bauen erzeugt
●  SSG           aus generateStaticParams erzeugt
ƒ  dynamisch     bei jeder Anfrage

Zwei Spalten lohnen den Blick. Das Symbol zeigt, ob deine Absicht aufgegangen ist. Und „First Load JS“ ist das JavaScript, das der Nutzer laden muss, bevor die Seite reagiert – steigt dieser Wert plötzlich, ist meist eine Client-Grenze zu weit oben gerutscht.

Tipp In die Prüfpipeline aufnehmen

Es lohnt sich, die Bauausgabe bei größeren Änderungen kurz anzusehen. Eine Seite, die unbemerkt von auf ƒ gewechselt ist, kostet ab dem Deploy bei jedem Aufruf Rechenzeit – und fällt sonst erst durch die Rechnung auf.

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 →