Czym jest Partial Prerendering?
Partial Prerendering (PPR) to model renderingu w Next.js, który pozwala na jednej stronie łączyć elementy statyczne (generowane w build time) z elementami dynamicznymi (renderowanymi na żądanie).
Do tej pory deweloperzy musieli wybierać: cała strona jest statyczna (SSG (Static Site Generation) to generowanie kompletnego HTML podczas budowania strony. Gotowe pliki serwujesz z CDN bez renderowania na żądanie — najszybszy i najtańszy model dla treści, która nie zmienia się przy każdej wizycie./ISR, czyli Incremental Static Regeneration, pozwala odświeżać strony statyczne w tle bez pełnego rebuildu — strona jest serwowana z cache, a Next.js regeneruje ją po upływie czasu revalidate.) albo cała jest dynamiczna (SSR, czyli Server-Side Rendering, to generowanie HTML na serwerze przy żądaniu — komponent client:only je pomija i renderuje się wyłącznie w przeglądarce.). PPR eliminuje ten wybór — statyczna powłoka strony jest serwowana natychmiast z CDN, czyli Content Delivery Network, to rozproszona sieć serwerów dostarczająca zasoby z węzła najbliższego użytkownikowi; CDN do obrazów dodatkowo transformuje je w locie., a dynamiczne „wyspy" Streaming to wysyłanie odpowiedzi HTML partiami, zanim wszystkie dane i komponenty będą gotowe. w tle.
W starszych wersjach Next.js PPR było pokazywane jako osobna, eksperymentalna funkcja. W aktualnych wersjach ten sam kierunek rozwija się pod nazwą Cache Components i opiera się na cacheComponents, dyrektywie "use cache" oraz Suspense.
To fundamentalna zmiana w architekturze frontendu. Zamiast decydować o modelu renderingu na poziomie strony — decydujesz na poziomie komponentu.
Jak PPR działa pod maską
PPR opiera się na trzech mechanizmach:
-
Statyczna powłoka — layout, nagłówek, nawigacja, footer i wszelkie treści, które nie zależą od requestu użytkownika. Generowane w build time, serwowane z CDN.
-
Dynamiczne wyspy (holes) — fragmenty strony opakowane w
<Suspense>, które wymagają danych zależnych od requestu (cookies, headers, params). -
Streaming — dynamiczne wyspy są renderowane na serwerze przy każdym requeście i streamowane do przeglądarki, wypełniając „dziury" w statycznej powłoce.
Włączenie PPR
W aktualnym podejściu włączasz ten model przez Cache Components:
Jeśli czytasz starsze materiały, zobaczysz jeszcze experimental.ppr = 'incremental' i export const experimental_ppr = true. To wcześniejszy etap tej samej idei. Dzisiaj praktycznym punktem odniesienia są cacheComponents, "use cache" i Suspense.
Oznaczanie strony jako PPR
W tym modelu nie oznaczasz już strony jedną flagą per-route. Zamiast tego oznaczasz statyczne fragmenty przez "use cache", a request-time islands opakowujesz w <Suspense>.
Co sprawia, że komponent jest dynamiczny?
Next.js automatycznie wykrywa, które komponenty są dynamiczne na podstawie użycia API zależnych od requestu:
Reguła jest prosta: jeśli komponent używa cookies(), headers(), searchParams, connection() lub fetch z cache: 'no-store', traktuj go jako request-time island i opakuj w <Suspense>. Statyczne fragmenty oznaczaj "use cache" albo cachuj ich dane na poziomie funkcji i komponentów.
PPR w praktyce — strona e-commerce
Najlepszym przykładem wartości PPR jest strona produktowa w sklepie internetowym.
Bez PPR: cała strona jest SSR (bo potrzebujesz spersonalizowanej ceny i stanu koszyka). TTFB, czyli Time To First Byte, mierzy czas od żądania do otrzymania pierwszego bajtu odpowiedzi z serwera. wynosi 200–500 ms.
Z PPR: 90% strony (layout, opis produktu, specyfikacja, footer) serwowane natychmiast z CDN (< 50 ms). Tylko cena i przycisk „dodaj do koszyka" renderują się dynamicznie.
PPR a SEO
PPR jest korzystny dla SEO z kilku powodów:
Szybszy TTFB
Statyczna powłoka dociera do przeglądarki (i crawlera) natychmiast. Google wyraźnie preferuje strony z niskim TTFB w Core Web Vitals.
Pełna treść dla crawlerów
W praktyce crawler najpewniej zobaczy statyczną powłokę bardzo szybko, a renderowanie dynamicznych wysp będzie zależeć od czasu odpowiedzi i procesu renderowania. Dlatego krytyczne elementy SEO, takie jak H1, lead, opis produktu i główna treść, najlepiej utrzymywać w statycznej shell, a nie odkładać ich do późno streamowanych komponentów.
Lepszy LCP
Największy element strony (hero image, tytuł produktu) jest częścią statycznej powłoki — pojawia się natychmiast, bez czekania na dynamiczne dane. Bezpośrednio przekłada się to na LCP, czyli Largest Contentful Paint, mierzy czas do wyrenderowania największego widocznego elementu — oznaczenie go preload przyspiesza jego załadowanie..
Ograniczenia PPR
Ewolucja API — od eksperymentu do stabilności
To obszar, który szybko dojrzewał, więc łatwo trafić na nieaktualne materiały. Wczesna flaga experimental.ppr została usunięta na rzecz Cache Components. W Next.js 16 cacheComponents to top-level config (już nie experimental), a dyrektywy "use cache", cacheLife i cacheTag są stabilne od 16.2 (zniknął prefiks unstable_). Jeśli czytasz tutorial z experimental_ppr = true albo unstable_cache, to treść sprzed stabilizacji — punktem odniesienia jest dziś cacheComponents.
Wymaga Suspense boundaries
Każdy dynamiczny fragment musi być opakowany w <Suspense>. Jeśli zapomnisz — cała strona stanie się dynamiczna, tracąc korzyści PPR.
Wymaga platformy z streaming
PPR potrzebuje hostingu obsługującego HTTP streaming. Vercel, AWS Lambda z streaming, self-hosted Node.js — tak. Statyczny export — nie.
Debugowanie
Ustalenie, które komponenty są statyczne, a które dynamiczne, może być nieoczywiste. Next.js dev mode pokazuje wskaźniki (Static Indicator), ale w złożonych drzewach komponentów zależności bywają trudne do wyśledzenia.
PPR vs inne modele renderingu
| Model | Generowanie | Personalizacja | TTFB | Użycie |
|---|---|---|---|---|
| SSG | Build time | Brak | Najszybszy | Blogi, docs, landing pages |
| ISR | Build + rewalidacja | Brak | Szybki | Produkty, artykuły z CMS |
| SSR | Każdy request | Pełna | Wolny | Dashboardy, panele admin |
| PPR | Hybryda | Częściowa | Szybki (powłoka z CDN) | E-commerce, strony z personalizacją |
PPR nie zastępuje SSG ani ISR — uzupełnia je. Strona czysto statyczna (blog, dokumentacja) nie potrzebuje PPR. Strona, która jest w 80% statyczna, ale ma 20% dynamicznej personalizacji — to idealny kandydat.
Jak przygotować się na PPR
Nawet jeśli nie włączysz PPR dzisiaj, możesz przygotować architekturę:
- Oddzielaj komponenty statyczne od dynamicznych — nie mieszaj
cookies()i statycznych danych w jednym komponencie - Używaj Suspense — każdy komponent z danymi powinien mieć boundary
- Cachuj agresywnie — dane, które mogą być statyczne, oznaczaj
cache: 'force-cache' - Przenoś dynamiczne API do dedykowanych komponentów —
cookies()iheaders()tylko w liściach drzewa komponentów
Te praktyki poprawią wydajność już teraz, a gdy PPR dojrzeje — migracja będzie bezbolesna.
