Next.js-Entwickler in Karlsruhe

Next.js für Unternehmen in Karlsruhe von einer Person: Datenabruf im App Router, Wasserfälle vermeiden, Streaming mit Suspense und loading.js, Partial Prerendering mit Cache Components. Erste schriftliche Schätzung kostenlos.

Next.js-Entwickler

Mein Platz in der WordPress-Community

  • Mein wordpress.org-Konto besteht seit 2006.
  • Ich habe zum WordPress-Core in den Versionen 7.0 und 7.1 beigetragen.
  • Ich betreue 30 Plugins auf wordpress.org.
  • Ich organisiere WordCamps und trete dort als Speaker auf.
  • Ich war bei jedem WordCamp Europe von 2017 bis 2026 dabei.
  • Lokales WordPress-Meetup: WordPress Meetup Karlsruhe

Mein WordPress.org-Profil

Mein Name ist Mariusz Szatkowski. Ich bin Einzelentwickler in Gdynia und arbeite seit 2006 mit WordPress. Für Karlsruhe schreibe ich über ein Problem, das bei Next.js-Projekten mit fremden Backends früh auftaucht: Die Daten kommen an, aber die Seite steht lange. Meine Angaben zu Next.js belegt die offizielle Dokumentation auf nextjs.org. Die npm-Registry führt als neueste Version 16.4.6 vom 9. November 2026.

#Ein langsames Backend hält die ganze Route an

Wer Daten in Server Components holt, ruft sie laut Dokumentation zum Datenabruf bei jeder Anfrage auf dem Server ab. Ist eine Anfrage langsam, ist die ganze Route blockiert, bis alle Daten da sind. Dazu kommt: fetch-Anfragen werden standardmäßig nicht gecacht und halten das Rendern an, bis sie fertig sind.

Das trifft vor allem Seiten, die sich auf Systeme stützen, die Sie nicht selbst steuern: Warenwirtschaft, Buchungssystem, Kundenverwaltung, eine Behörden-Schnittstelle. Als Beispiel für so eine Schnittstelle nehme ich das Transparenzportal der Stadt Karlsruhe. Es läuft laut Startseite auf CKAN 2.11.3 und beantwortet JSON-Anfragen unter /api/3/action/. Zwei Aktionen aus der CKAN-Dokumentation genügen für die Beispiele unten: package_show für einen Datensatz und package_search für die Suche.

Marktplatz in Karlsruhe mit Pyramide und Rathaus

Foto: Sitacuisses, CC BY-SA 3.0 de, Wikimedia Commons.

#Nacheinander, gleichzeitig, abhängig

Layouts und Seiten rendern laut Dokumentation standardmäßig parallel, jedes Segment beginnt also so früh wie möglich mit dem Laden. Innerhalb einer einzelnen Komponente gilt das nicht: Mehrere await-Aufrufe können dort nacheinander laufen, auch wenn sie nichts voneinander brauchen.

MusterWas passiert
Zwei await hintereinander in einer KomponenteDie zweite Anfrage startet erst, wenn die erste fertig ist
Anfragen starten, dann Promise.allBeide laufen gleichzeitig, die Wartezeit ist die der langsamsten
Die zweite Anfrage braucht das Ergebnis der erstenEchte Abhängigkeit, bleibt nacheinander

Die erste Variante sieht harmlos aus:

const datensatz = await getDatensatz(id)
const aehnliche = await sucheDatensaetze('Gebäude')

Die Suche wartet hier auf einen Datensatz, den sie gar nicht braucht. Die Dokumentation zeigt den Ausweg: Anfragen zuerst anstoßen, dann gemeinsam abwarten.

// app/datensatz/[id]/page.tsx
const API = 'https://transparenz.karlsruhe.de/api/3/action'

async function ckan(action: string, query: Record<string, string>) {
  const res = await fetch(`${API}/${action}?${new URLSearchParams(query)}`)
  if (!res.ok) throw new Error(`${action}: ${res.status}`)
  return (await res.json()).result
}

const getDatensatz = (id: string) => ckan('package_show', { id })
const sucheDatensaetze = (q: string) =>
  ckan('package_search', { q, rows: '5' })

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

  const [datensatz, aehnliche] = await Promise.all([
    getDatensatz(id),
    sucheDatensaetze('Gebäude'),
  ])

  return <h1>{datensatz.title}</h1>
}

Ich habe die beiden Hilfsfunktionen mit Node gegen das Portal laufen lassen: Beide Aufrufe kamen zurück, und mit Promise.allSettled bleibt ein fehlerhafter Aufruf von einem funktionierenden getrennt. Das ist der zweite Hinweis der Dokumentation: Schlägt bei Promise.all eine Anfrage fehl, schlägt die ganze Operation fehl. Wo eine Teilantwort reicht, nehmen Sie Promise.allSettled.

#Wenn die Abhängigkeit echt ist

Braucht die zweite Anfrage das Ergebnis der ersten, etwa die Kunden-ID aus dem ersten Aufruf, bleibt die Reihenfolge. Die Dokumentation rät dann, die abhängige Komponente in eine eigene <Suspense>-Grenze zu setzen. Die Seite wartet trotzdem auf die erste Antwort, bevor sie etwas zeigt. Die Dokumentation nennt zwei Auswege: die ganze Seite in eine Suspense-Grenze legen, zum Beispiel mit loading.js, und die erste Anfrage so schnell machen wie möglich. Ändern sich die Daten selten, kommt Caching in Frage.

#Eine Anfrage weniger

Manche Wasserfälle sind gar keine Abhängigkeit. Bei meinem Abruf am 11. November 2026 enthielt jedes Ergebnis von package_search bereits die Liste der Ressourcen. Ein zweiter Aufruf pro Treffer wäre eine Kette ohne Grund gewesen. Bevor ich eine Anfrage parallelisiere, lese ich deshalb die Antwort der vorigen: Oft steht darin schon, was die nächste holen sollte.

#Früher starten mit Preload und React.cache

Manchmal blockiert andere Arbeit eine Anfrage, deren Eingaben längst feststehen. Die Dokumentation beschreibt dafür Preloading: Die Funktion wird ohne await vor der blockierenden Arbeit aufgerufen, danach ruft die Komponente dieselbe Funktion auf und nutzt die bereits laufende Anfrage.

// app/item/[id]/item.tsx
async function getItem(id: string) {
  const res = await fetch(`https://api.example.com/items/${id}`)
  return res.json()
}

export const preload = (id: string) => {
  void getItem(id)
}

Das funktioniert, weil identische fetch-Aufrufe in einem Komponentenbaum automatisch zusammengeführt werden. Für eine Datenbank oder ein SDK ohne fetch wickeln Sie die Funktion in React.cache. Der Geltungsbereich ist laut Dokumentation eine einzelne Anfrage: Zwischen Besuchern wird nichts geteilt.

#Streaming: loading.js oder Suspense

Streaming zerlegt die Seite in Teile, die der Server nach und nach schickt. Die Dokumentation nennt zwei Wege: loading.js für die ganze Route und <Suspense> für einzelne Komponenten.

loading.js<Suspense>
Geltungsbereichganze Seitejede Komponente
Aufwandeine DateiKomponenten einzeln umschließen
Navigationals sofortiger Platzhalter vorgeladenstandardmäßig nicht vorgeladen
Geeignet fürSeiten, die ohne Daten nichts zeigendie meisten Seiten, feinere Kontrolle

Zwei Stolpersteine stehen in der Dokumentation zu loading.js. Erstens umschließt die Datei page.js und alles darunter, aber nicht das layout.js desselben Segments. Holt das Layout ungecachte Daten, greift der Platzhalter dort nicht, und die Navigation wartet. Zweitens gilt für Suspense-Grenzen das Gegenstück: Wer params, cookies() oder eine Datenabfrage ganz oben in einem Layout oder einer Seite abwartet, macht alles darunter dynamisch. Die Streaming-Anleitung rät, das Warten an die Komponente zu verschieben, die die Daten wirklich braucht.

Mehrere Komponenten mit eigener Suspense-Grenze laden unabhängig voneinander, in der Reihenfolge, in der ihre Daten ankommen. Eine Seite mit Kopfzeile, Umsatzkennzahlen und einer Liste aus einem langsamen System zeigt dann die Kopfzeile sofort, und die Liste kommt, wenn das System antwortet.

#Partial Prerendering heute

Wer nach Partial Prerendering sucht, findet es in der aktuellen Dokumentation unter Caching. Es ist das Standardverhalten, wenn cacheComponents aktiviert ist:

// next.config.ts
import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
  cacheComponents: true,
  partialPrefetching: true,
}

export default nextConfig

Neue Apps aus create-next-app haben beide Optionen laut Dokumentation bereits an. Die Route besteht dann aus einer statischen Hülle, die beim Build entsteht und sofort ausgeliefert wird, und aus Teilen, die hinter ihrer Suspense-Grenze nachstreamen. Greift ein Teil auf ungecachte oder anfragebezogene Daten zu, ohne dass eine Grenze darum liegt, bricht der Build mit einem Fehler ab, statt die Seite stillschweigend zu blockieren. Für Projekte ohne Cache Components beschreibt die Dokumentation das frühere Modell in einer eigenen Anleitung. Wie Zeitgrenzen und Revalidierung für Inhalte aussehen, die sich ändern, steht auf der Seite für Augsburg.

#Was Streaming kostet

Streaming ist keine reine Beschleunigung. Vier Punkte aus der Dokumentation:

  • Statuscode. Sobald der Stream beginnt, ist 200 gesendet. Ein notFound() mitten im Stream liefert deshalb keinen 404, Next.js ergänzt ein noindex-Meta-Tag. Die Prüfung gehört vor die Suspense-Grenze, nach dem Muster aus der Anleitung: erst schnell prüfen, ob der Datensatz existiert, dann streamen. Ein Request-Time-404 geht über Proxy.
  • Bots. Bots, die nur HTML lesen, bekommen die Metadaten im <head> der ersten Antwort; Next.js wartet dafür auf generateMetadata. Die Seite ist laut Dokumentation für die Suche trotzdem nicht benachteiligt.
  • LCP und CLS. Das größte Element im Sichtbereich bleibt außerhalb von Suspense-Grenzen, sonst erscheint es erst beim Austausch. Die Schwelle für LCP liegt bei bis zu 2,5 s, für CLS bei bis zu 0,1. Platzhalter sollten die Größe des späteren Inhalts haben, damit nichts springt.
  • Puffer. Reverse Proxys wie nginx puffern Antworten standardmäßig. Dann sieht der Besucher eine einzige späte Antwort statt eines Stroms. Der Header X-Accel-Buffering: no schaltet das ab. CDNs und Kompression können dasselbe bewirken. Ob Streaming bei Ihnen wirklich ankommt, prüfe ich am rohen Antwortstrom, nicht an einem Bauchgefühl.

#Schnittstellen und Datenschutz: was der LfDI Baden-Württemberg verlangt

Server Components rufen Schnittstellen im Namen Ihrer Besucher auf, oft mit personenbezogenen Daten: Kundennummer, Buchungsdaten, Anfragen an ein CRM. Verarbeitet der Betreiber der Schnittstelle diese Daten in Ihrem Auftrag, ist das Auftragsverarbeitung. Die Praxishilfe des LfDI Baden-Württemberg hält dazu fest, dass sie nur auf Grundlage eines bindenden Vertrags erfolgen darf. Der Vertrag muss Gegenstand, Dauer, Art und Zweck der Verarbeitung, die Art der Daten, die Kategorien der Betroffenen und die Pflichten beider Seiten festlegen. Er muss schriftlich oder in einem elektronischen Format vorliegen; nicht jede bestätigende E-Mail genügt, aber ein dokumentiertes Häkchen kann es.

Das ist keine Rechtsberatung. Für die Technik folgt daraus eine Aufgabe, die ich schriftlich erledige: Ich liste, welche Anfrage mit welchen Daten an welches System geht und ob das im Browser oder auf dem Server passiert. Diese Liste bekommt Ihre Rechtsberatung, bevor ein Vertrag aufgesetzt wird.

#Checkliste vor dem Projekt

FrageWarum sie zählt
Wie viele Anfragen braucht die Seite, und welche hängen wirklich voneinander ab?Nur echte Abhängigkeiten dürfen nacheinander laufen
Liefert eine Antwort schon, was die nächste Anfrage holen würde?Spart eine Anfrage
Welche Teile der Seite können ohne Daten angezeigt werden?Das ist die statische Hülle
Welcher Teil ist der größte sichtbare Inhalt?Er gehört nicht hinter eine Suspense-Grenze
Holt ein Layout ungecachte Daten?Dann greift loading.js dort nicht
Läuft ein Proxy oder CDN vor der Anwendung?Er kann das Streaming puffern
Verarbeitet ein angebundenes System personenbezogene Daten für Sie?Dann braucht es einen Vertrag nach Art. 28 DSGVO

#So läuft ein Projekt mit mir

Ich arbeite allein, aus der Ferne und schriftlich, ohne Termine und Telefonate. Am Anfang steht Ihre Mail mit Ziel, Stack und Frist. Ich beantworte sie mit meinen Fragen und einer schriftlichen Beschreibung von Umfang und Annahmen. Ich baue auf einer Staging-Umgebung, Sie geben schriftlich frei, dann folgt der Livegang. Für das Datenabruf-Thema gehört ein Anfrageplan dazu: eine Tabelle der Schnittstellen mit Reihenfolge, Abhängigkeiten und der Stelle, an der gestreamt wird. Das Layout liefern Sie als Wireframe, ich setze es um. Die Pflege danach übernehme ich auf Wunsch, ohne dass Stunden in den nächsten Monat wandern. Wer ein Backend dahinter braucht, findet die Seite zu PHP-Entwicklung in Karlsruhe, und für einen Shop mit Headless-Frontend die Seite zu Shopify in Karlsruhe.

#Häufige Fragen

Warum ist meine Next.js-Seite langsam, obwohl das Backend nur eine Sekunde braucht? Häufig laufen mehrere Anfragen nacheinander. Laut Dokumentation können mehrere await-Aufrufe in einer Komponente sequenziell sein, auch wenn sie nichts voneinander brauchen. Starten Sie die Anfragen zuerst und warten Sie dann mit Promise.all auf alle. Ist eine Anfrage wirklich abhängig, kommt die Komponente, die ihr Ergebnis braucht, in eine eigene Suspense-Grenze.

Reicht eine loading.js-Datei für Streaming? Für eine ganze Route ja. Die Datei umschließt page.js und alles darunter mit einer Suspense-Grenze. Das layout.js desselben Segments gehört nicht dazu: Holt das Layout ungecachte Daten, hilft die Datei dort nicht. Die Dokumentation empfiehlt Suspense nahe an der Stelle, die auf Daten wartet.

Was ist aus Partial Prerendering geworden? Es ist laut Dokumentation das Standardverhalten, sobald cacheComponents aktiviert ist. Die statische Hülle einer Route wird vorab erzeugt und sofort ausgeliefert, ungecachte oder anfragebezogene Teile streamen hinter ihrer Suspense-Grenze nach.

Schadet Streaming der Auffindbarkeit bei Google? Die Dokumentation sagt nein: Streaming wird auf dem Server gerendert. Zwei Dinge sind zu beachten. Für Bots, die nur HTML lesen, wartet Next.js auf generateMetadata. Und ein notFound() mitten im Stream liefert Status 200 mit noindex, nicht 404. Prüfungen, die einen 404 auslösen sollen, gehören vor die Suspense-Grenze.

Brauche ich für Schnittstellen einen Vertrag zur Auftragsverarbeitung? Wenn der Betreiber der Schnittstelle in Ihrem Auftrag personenbezogene Daten verarbeitet, verlangt der LfDI Baden-Württemberg einen bindenden Vertrag nach Art. 28 DSGVO. Ob das auf Ihren Fall zutrifft, klärt Ihre Rechtsberatung. Ich liste vorher, welche Anfrage welche Daten wohin schickt.

Gestalten Sie auch das Layout? Nein. Gestaltung und Wireframes kommen vom Auftraggeber. In einer Tabellenvorlage tragen Sie ein, welches Element wohin gehört; ich setze das responsiv um.

#Ihr Projekt in einer E-Mail

Ist eine Seite in Karlsruhe langsam, weil ein System im Hintergrund träge antwortet, oder soll eine neue Anwendung gleich so gebaut werden, dass sie schnell sichtbar wird? Ihre Nachricht erreicht mich über das Kontaktformular. Nennen Sie die Adresse der Anwendung, das Backend dahinter, Ihr Ziel und den Wunschtermin. Die erste schriftliche Schätzung ist kostenlos; ich melde mich an Werktagen mit Rückfragen.

Brauchen Sie die Leistung: Next.js-Entwickler in Karlsruhe?

Beschreiben Sie Ihr Projekt per E-Mail. Antwort innerhalb von 48 Stunden.

Projekt beschreiben

Weitere WordPress-Dienste und Wissensbasis entdecken