Wybór metody renderowania to jedna z decyzji, które najtrudniej zmienić po starcie projektu. Od niej zależy, co zobaczy Googlebot i inne roboty, jak szybko strona pokaże treść na telefonie, ile będzie kosztować serwer i jak bardzo skomplikowane będzie wdrażanie zmian. Przy projektach, które prowadzę, nie wybieram jednej metody dla całego serwisu, tylko dobieram ją do typu podstrony. W tym wpisie pokazuję, czym w praktyce różnią się CSR, SSR, SSG i ISR, według jakich kryteriów wybieram metodę i jak sprawdzam, czy wybór nie zaszkodził SEO.
Gdzie i kiedy powstaje HTML
Wszystkie cztery metody odpowiadają na to samo pytanie: kiedy i gdzie powstaje gotowy kod HTML z treścią strony. Różnice najlepiej widać zestawione obok siebie:
| Metoda | Kiedy powstaje HTML | Co dostaje robot w pierwszej odpowiedzi | Obciążenie serwera |
|---|---|---|---|
| CSR (renderowanie w przeglądarce) | w przeglądarce, po pobraniu i wykonaniu JavaScriptu | prawie pusty dokument i skrypty | niskie, pliki statyczne |
| SSR (renderowanie na serwerze) | na serwerze, przy każdym żądaniu | pełną treść | najwyższe, zależy od ruchu i pamięci podręcznej |
| SSG (generowanie statyczne) | raz, podczas budowania strony | pełną treść | minimalne, pliki z CDN |
| ISR (odświeżanie przyrostowe) | przy budowaniu lub pierwszym żądaniu, potem odświeżany w tle | pełną treść, czasem sprzed kilku minut | niskie |
Warto pamiętać, że SSR nie oznacza wyłącznie Next.js czy Nuxt. Klasyczny WordPress, PrestaShop czy aplikacja w PHP to również renderowanie na serwerze przy każdym żądaniu, tylko bez warstwy JavaScriptu przejmującej stronę w przeglądarce. Różnica dotyczy tylko tego, co dzieje się dalej, gdy zaczyna się działanie strony internetowej w przeglądarce.
CSR w praktyce
Przy CSR serwer zwraca pusty dokument, a treść pojawia się dopiero po pobraniu i wykonaniu skryptów oraz pobraniu danych z API. Pierwsza odpowiedź serwera jest szybka, ale użytkownik na słabszym telefonie długo patrzy na pusty ekran albo szkielet strony, więc cierpi LCP.
Dla SEO to największe ryzyko z czterech metod. Google renderuje JavaScript, ale robi to w osobnym etapie, czasem z opóźnieniem, i tylko wtedy, gdy skrypty zadziałają bez błędów. Wiele robotów, w tym większość botów AI i narzędzi do podglądu linków, w ogóle nie uruchamia JavaScriptu i widzi pustą stronę. Dlatego CSR stosuję wyłącznie tam, gdzie indeksowanie nie ma znaczenia:
- panele klienta i konta użytkowników,
- kokpity z danymi i raportami,
- konfiguratory i kalkulatory dostępne po zalogowaniu,
- narzędzia wewnętrzne firmy.
SSR w praktyce
SSR wybieram tam, gdzie treść musi być aktualna przy każdym żądaniu albo zależy od użytkownika:
- wyniki wyszukiwania wewnętrznego i filtrowania,
- strony z dostępnością lub cenami zmieniającymi się w czasie rzeczywistym,
- treści zależne od lokalizacji, języka lub zalogowanego użytkownika.
Robot dostaje pełny HTML, ale każdy zysk zależy od tego, jak szybko odpowiada serwer. Bez pamięci podręcznej SSR przy dużym ruchu potrafi mieć wyższy czas odpowiedzi niż jakakolwiek inna metoda.
W frameworkach JavaScript dochodzi koszt hydratacji, czyli ponownego uruchomienia komponentów w przeglądarce, żeby strona stała się interaktywna. Przy rozbudowanych stronach to długie zadania w głównym wątku, które pogarszają INP. Znajduję je i rozbijam tak samo jak przy refaktoryzacji JavaScriptu pod kątem INP.
SSG w praktyce
SSG to mój domyślny wybór dla:
- stron firmowych i ofertowych,
- blogów i serwisów z poradnikami,
- dokumentacji technicznych,
- stron produktowych w małych sklepach, w których ceny zmieniają się rzadko.
Gotowe pliki HTML trafiają do CDN, więc strona odpowiada w kilkadziesiąt milisekund, a serwer z bazą danych może być w ogóle niedostępny z internetu. Z takiego połączenia korzystam m.in. przy WordPressie jako panelu treści i Astro jako generatorze, czyli w architekturze headless CMS.
Ograniczeniem jest czas budowania. Przy dziesiątkach tysięcy podstron każda zmiana w szablonie oznacza przebudowę całości, która może trwać długo, a zmiana ceny czy stanu magazynowego nie pojawi się na stronie, dopóki strona nie zostanie zbudowana od nowa.
ISR w praktyce
ISR rozwiązuje problem czasu budowania: strony są generowane jak statyczne, ale każda odświeża się osobno, po określonym czasie albo na
sygnał z CMS-a, np. po zmianie produktu. Nazwa pochodzi z Next.js, ale ten sam efekt da się osiągnąć w innych narzędziach przez pamięć
podręczną CDN z odświeżaniem w tle, czyli nagłówki Cache-Control z dyrektywą stale-while-revalidate.
Ceną jest możliwość pokazania nieaktualnej treści przez krótki czas. Dla opisu produktu to bez znaczenia, dla ceny w trakcie promocji już tak. Dlatego przy sklepach odświeżam strony na żądanie, wywołaniem z CMS-a po zmianie danych, a nie tylko co ustalony czas. Czyszczenie pamięci podręcznej na żądanie to też podstawa, którą ustawiam przy każdej konfiguracji CDN.
Jak dobieram metodę do typu podstrony
Nowoczesne narzędzia, takie jak Next.js, Nuxt czy Astro, pozwalają łączyć metody w jednym projekcie. Ja ustalam metodę dla każdego szablonu osobno:
| Typ podstrony | Metoda, którą wybieram | Dlaczego |
|---|---|---|
| strona główna, strony ofertowe, blog | SSG | treść zmienia się rzadko, liczy się szybkość i pełny HTML |
| karta produktu i kategoria w dużym sklepie | ISR lub SSR z pamięcią podręczną | dużo podstron, ceny i stany zmieniają się często |
| wyniki wyszukiwania wewnętrznego i filtry | SSR | każde zapytanie daje inny wynik |
| koszyk, panel klienta, konfigurator | CSR lub SSR bez indeksowania | treść zależy od użytkownika i nie trafia do wyszukiwarki |
| elementy interaktywne na stronach statycznych | tylko wybrane komponenty uruchamiane w przeglądarce | reszta strony zostaje lekkim HTML |
Ostatni wiersz to podejście, które coraz częściej stosuję: strona jest generowana statycznie, a JavaScript dostają tylko te fragmenty, które tego wymagają, np. wyszukiwarka czy galeria. W Astro działa to domyślnie. Nie każdy projekt potrzebuje przy tym frameworka, a wybór narzędzia ponad potrzeby to typowy przykład overengineeringu w stronach internetowych.
Jak sprawdzam, co widzi Google
- Pobieram stronę bez wykonywania JavaScriptu, np. poleceniem
curlalbo przez podgląd źródła, i sprawdzam, czy treść, tytuł, opis, linki i dane strukturalne są w HTML. - W Search Console używam narzędzia do sprawdzania adresów URL i porównuję wyrenderowany kod z tym, co widzę w przeglądarce.
- Crawluję serwis z renderowaniem i bez niego, żeby wychwycić linki i treści, które istnieją tylko po uruchomieniu skryptów.
- Sprawdzam wskaźniki Core Web Vitals dla każdego typu szablonu osobno, bo różne metody renderowania psują różne wskaźniki.
Jeśli treść pojawia się dopiero po uruchomieniu JavaScriptu, nie serwuję robotom osobnej wersji, tylko przenoszę renderowanie na serwer. Osobna wersja dla robotów to obejście, które łatwo przekroczy granicę, jaką wyznacza dynamic rendering a cloaking.