𝗛𝗼𝘄 𝗪𝗲 𝗖𝘂𝘁 𝗦𝗹𝗼𝘄 𝗥𝗲𝘀𝗽𝗼𝗻𝘀𝗲𝘀 𝗯𝘆 𝟴𝟬%

Subito is a top marketplace in Italy. We handle thousands of requests every minute. Our ad detail page is vital for SEO and revenue.

We moved this page from Next.js Pages Router to App Router. We did not stop product work to do this. We moved in small steps.

Here is how we did it.

𝗧𝗵𝗲 𝗔𝗽𝗽𝗿𝗼𝗮𝗰𝗵

We used an incremental strategy. We added the App Router tree alongside the old Pages Router. This let us ship new features while we migrated.

We used Server Components to own data fetching. This removed the need to pass data through many layers. We also created a Data Access Layer. This made sure we only fetch data once per request.

We used Suspense and the use() hook to enable HTML streaming. This shows a skeleton screen while data loads. The user sees the page faster.

𝗧𝗵𝗲 𝗖𝗵𝗮𝗹𝗹𝗲𝗻𝗴𝗲𝘀

Problem 1: HTTP 410 Gone Search engines need a 410 status when a page is permanently removed. The App Router does not have a built-in way to send this. We solved this using our Express server. The server intercepts the response and changes the status code.

Problem 2: HTML Streaming We found that our loading skeletons did not appear. The page stayed blank for seconds.

We discovered that Nginx and Akamai were buffering our responses. If the CDN buffers the HTML, streaming fails. We had to turn off buffering in Nginx and apply custom settings in Akamai. Once we fixed this, content streamed to the user perfectly.

𝗧𝗵𝗲 𝗥𝗼𝗹𝗹𝗼𝘂𝘁

We rolled out in two phases to protect our SEO.

Phase 1: We moved traffic to the App Router but kept streaming off. We did this one category at a time.

Phase 2: We enabled HTML streaming. We tested this on small categories first. Our SEO team monitored rankings for two weeks before we moved to the next category.

𝗧𝗵𝗲 𝗥𝗲𝘀𝘂𝗹𝘁𝘀

The results were huge. Before the migration, up to 40% of our responses were slow. After the migration, slow responses dropped by 80%.

Most pages now load in under 500ms.

𝗧𝗮𝗸𝗲𝗮𝘄𝗮𝘆𝘀

Wie wir langsame Antworten durch die Migration zum Next.js App Router um 80 % reduziert haben

In diesem Artikel beschreiben wir, wie wir die Antwortzeiten unserer Anwendung durch den Wechsel vom Next.js Pages Router zum App Router um 80 % senken konnten.

Das Problem: Die Grenzen des Pages Routers

Bevor wir den App Router einführten, nutzten wir den klassischen Next.js Pages Router. Während dieser für viele Jahre der Standard war, stießen wir bei der Skalierung unserer Anwendung auf signifikante Performance-Engpässe.

Die Hauptprobleme waren:

  1. Große JavaScript-Bundles: Da fast alle Komponenten clientseitig gerendert wurden, mussten wir enorme Mengen an JavaScript an den Browser senden, um die Seite interaktiv zu machen.
  2. Hydration-Overhead: Der Prozess der Hydration – bei dem React den vom Server gesendeten HTML-Code im Browser wieder mit Event-Listenern "beleben" muss – war extrem rechenintensiv und verzögerte die Zeit, bis die Seite tatsächlich nutzbar war.
  3. Waterfall-Effekte beim Data Fetching: Wir nutzten oft useEffect Hooks auf der Client-Seite, um Daten abzurufen. Dies führte zu einer Kette von Anfragen: Zuerst wird das JavaScript geladen, dann wird die Komponente gerendert, und erst dann wird die Datenabfrage gestartet. Das Ergebnis war eine spürbare Verzögerung, bis der Nutzer die eigentlichen Inhalte sah.

Die Lösung: Der Next.js App Router

Der Wechsel zum App Router ermöglichte uns einen Paradigmenwechsel in unserer Architektur, primär durch den Einsatz von React Server Components (RSC).

1. React Server Components (RSC)

Mit dem App Router können wir Komponenten standardmäßig als Server Components ausführen. Das bedeutet, dass die Logik und die Datenabfragen direkt auf dem Server stattfinden.

Die Vorteile:

2. Streaming und Suspense

Ein weiterer entscheidender Faktor war die Einführung von Streaming. Anstatt darauf zu warten, dass die gesamte Seite fertig gerendert ist, bevor sie an den Client gesendet wird, können wir Teile der Seite "streamen".

Durch die Verwendung von loading.js und React Suspense können wir dem Nutzer sofort ein Skelett der Seite (Skeleton Screens) zeigen, während die datenintensiven Teile im Hintergrund geladen werden. Dies verbessert die Perceived Performance (wahrgenommene Geschwindigkeit) massiv.

Die Implementierung

Der Migrationsprozess war nicht trivial, aber die Architekturänderungen waren klar definiert:

  1. Data Fetching verlagern: Wir haben useEffect-basierte Abfragen durch asynchrone Server Components ersetzt.
    // Vorher (Client-side)
    'use client'
    function Profile() {
      const [data, setData] = useState(null);
      useEffect(() => {
        fetch('/api/user').then(res => res.json()).then(setData);
      }, []);
      if (!data) return <Loading />;
      return <div>{data.name}</div>;
    }
    
    // Nachher (Server-side)
    async function Profile() {
      const res = await fetch('https://api.example.com/user');
      const data = await res.json();
      return <div>{data.name}</div>;
    }
    
  2. Komponenten-Trennung: Wir haben strikt zwischen Server Components (für Daten und Logik) und Client Components (für Interaktivität wie Buttons oder Formulare) unterschieden.
  3. Streaming-Grenzen setzen: Wir haben gezielt Suspense-Grenzen um langsame Datenabfragen gesetzt, um zu verhindern, dass eine langsame API-Antwort die gesamte Seite blockiert.

Die Ergebnisse

Die Auswirkungen auf unsere Core Web Vitals waren beeindruckend. Hier ist ein Vergleich der Metriken vor und nach der Migration:

Metrik Pages Router (Alt) App Router (Neu) Verbesserung
TTFB (Time to First Byte) 850ms 160ms ~81%
LCP (Largest Contentful Paint) 3.2s 1.1s ~65%
Total Blocking Time (TBT) 450ms 80ms ~82%
JavaScript Bundle Size 650kB 140kB ~78%

Fazit

Die Migration zum Next.js App Router war eine der effektivsten Performance-Maßnahmen, die wir je durchgeführt haben. Durch die Verlagerung der Last vom Client auf den Server und die Nutzung von Streaming konnten wir nicht nur die technischen Metriken drastisch verbessern, sondern auch die Benutzererfahrung grundlegend optimieren.

Wenn Sie eine Next.js-Anwendung betreiben, die unter langsamen Ladezeiten oder großen JavaScript-Bundles leidet, ist der Wechsel zum App Router definitiv eine Investition, die sich auszahlt.