Optymalizacja stron w Next.js
Praktyczny przewodnik po optymalizacji stron w Next.js — od wyboru strategii renderowania, przez obrazy i czcionki, po cache i Core Web Vitals.

Next.js daje wiele możliwości tworzenia szybkich stron i aplikacji internetowych, ale sama technologia nie gwarantuje dobrej wydajności. Na szybkość działania wpływa sposób renderowania strony, rozmiar przesyłanych plików, obrazy, czcionki, cache danych oraz ilość JavaScriptu, który musi zostać pobrany i wykonany w przeglądarce użytkownika.
Dobra optymalizacja polega na tym, aby nie wykonywać niepotrzebnej pracy. Serwer nie powinien generować od nowa treści, które rzadko się zmieniają, a przeglądarka nie powinna pobierać kodu, który nie jest potrzebny przy pierwszym wejściu na stronę. W Next.js wiele z tych elementów można kontrolować już na poziomie architektury aplikacji.
Strategia renderowania: SSG, SSR i ISR
Strategia renderowania: SSG, SSR i ISR
Jedną z najważniejszych decyzji w Next.js jest wybór sposobu renderowania strony. W praktyce warto zacząć od prostego pytania: jak często zmienia się dana treść i czy musi być generowana indywidualnie dla każdego użytkownika?
Jeżeli strona zawiera treści stałe, na przykład wpis blogowy, podstronę ofertową, landing page albo opis usługi, dobrym wyborem będzie SSG, czyli statyczne generowanie strony. Taka strona powstaje wcześniej, podczas budowania aplikacji, a następnie może być szybko dostarczana użytkownikom z CDN. Dzięki temu serwer nie musi tworzyć jej od nowa przy każdym wejściu.
Jeżeli treść zmienia się co jakiś czas, ale nie wymaga pełnego przebudowania aplikacji po każdej aktualizacji, warto wykorzystać ISR. Ten mechanizm pozwala odświeżać statycznie wygenerowane strony po określonym czasie lub po konkretnej zmianie danych. Sprawdza się na przykład przy stronach produktowych, artykułach, aktualnościach albo podstronach, które są aktualizowane, ale nie co kilka sekund.
Z kolei SSR warto stosować wtedy, gdy treść zależy od konkretnego użytkownika, sesji albo aktualnego żądania. Przykładem może być koszyk, panel klienta, indywidualne dane konta albo widok zależny od uprawnień. Trzeba jednak pamiętać, że każda taka strona wymaga pracy serwera w momencie wejścia użytkownika, dlatego SSR powinien być używany świadomie.
W App Routerze komponenty domyślnie działają po stronie serwera. To dobre podejście, ponieważ ogranicza ilość kodu JavaScript wysyłanego do przeglądarki. Komponenty klienckie warto stosować dopiero wtedy, gdy są naprawdę potrzebne, na przykład przy interakcjach, formularzach, mapach, filtrach lub elementach zależnych od API przeglądarki.
Optymalizacja obrazów z next/image
Obrazy bardzo często mają największy wpływ na wagę strony. Nawet dobrze zaprojektowana aplikacja może działać wolno, jeśli użytkownik musi pobrać zbyt duże grafiki. Właśnie dlatego w Next.js warto korzystać z komponentu next/image.
Ten komponent pomaga automatycznie dostarczać obrazy w nowoczesnych formatach, takich jak AVIF lub WebP. Dodatkowo obsługuje responsywne rozmiary i lazy loading, czyli ładowanie obrazów dopiero wtedy, gdy są potrzebne. Dzięki temu użytkownik nie musi od razu pobierać wszystkich grafik znajdujących się na stronie.
Przy obrazach trzeba pamiętać o kilku zasadach. Warto ustawiać width i height albo używać fill, aby przeglądarka od początku znała miejsce przeznaczone na grafikę. Pomaga to uniknąć przesuwania się układu strony podczas ładowania, czyli problemu z metryką CLS.
Dla najważniejszego obrazu widocznego od razu po wejściu na stronę, na przykład grafiki w sekcji hero, można dodać priority. Dzięki temu przeglądarka potraktuje ten obraz jako ważniejszy i pobierze go szybciej. Pozostałe grafiki najczęściej powinny ładować się dopiero wtedy, gdy użytkownik przewinie stronę w ich okolice.
Istotne jest także poprawne ustawienie sizes. Jeżeli obraz w projekcie ma realnie 600 pikseli szerokości, nie ma sensu pobierać znacznie większego wariantu. Zbyt duże pliki zwiększają transfer, wydłużają czas ładowania i pogarszają doświadczenie użytkownika.
Code splitting i dynamiczny import
Nie każdy element strony musi być ładowany od razu. Jeżeli aplikacja wysyła do przeglądarki zbyt dużo JavaScriptu, użytkownik dłużej czeka, aż strona stanie się w pełni interaktywna. Dotyczy to szczególnie rozbudowanych komponentów, takich jak mapy, wykresy, edytory tekstu, modale, konfiguratory albo zaawansowane filtry.
W takich przypadkach warto stosować dynamiczny import przez next/dynamic. Dzięki temu ciężki komponent może zostać pobrany dopiero wtedy, gdy rzeczywiście będzie potrzebny. Przykładowo mapa nie musi być częścią pierwszego ładowania strony, jeżeli znajduje się niżej albo otwiera się dopiero po kliknięciu.
Warto też uważać na dyrektywę 'use client'. Im wyżej w strukturze komponentów zostanie użyta, tym większa część aplikacji trafi do kodu wykonywanego w przeglądarce. Lepszym rozwiązaniem jest oznaczanie jako klienckich tylko tych komponentów, które naprawdę wymagają interakcji po stronie użytkownika.
Logikę pobierania danych dobrze jest zostawiać w komponentach serwerowych, o ile nie ma potrzeby wykonywania jej w przeglądarce. Dzięki temu aplikacja może być lżejsza, szybsza i prostsza do utrzymania.
Optymalizacja czcionek z next/font
Czcionki również wpływają na szybkość ładowania strony. Jeżeli są pobierane z zewnętrznego serwera, przeglądarka musi wykonać dodatkowe żądania, zanim wyświetli tekst w docelowym kroju. To może opóźniać renderowanie i powodować widoczne przeskoki treści.
W Next.js można temu zapobiec za pomocą next/font. Mechanizm ten pozwala hostować pliki czcionek lokalnie podczas budowania aplikacji. Dzięki temu aplikacja nie musi pobierać ich z zewnętrznego źródła, a przeglądarka może szybciej wyświetlić stronę.
Nie oznacza to jednak, że warto ładować wszystkie dostępne odmiany fontu. Każda dodatkowa grubość, styl lub zestaw znaków zwiększa wagę strony. Najlepiej ograniczyć się do tych wariantów, które są faktycznie używane w projekcie, na przykład regular, medium i bold.
Dobrze skonfigurowane fonty pomagają też ograniczyć CLS, czyli przesunięcia układu strony. Jeżeli przeglądarka ma odpowiedni fallback o podobnych wymiarach, tekst nie zmienia gwałtownie swojego położenia po załadowaniu docelowej czcionki.
Cache i rewalidacja danych
Next.js pozwala cache’ować zarówno wyniki zapytań fetch, jak i całe segmenty trasy. Oznacza to, że aplikacja nie musi pobierać tych samych danych przy każdym wejściu użytkownika. Dobrze ustawiony cache może znacząco poprawić szybkość działania strony i zmniejszyć obciążenie serwera.
Przy danych, które nie zmieniają się co chwilę, warto ustawić revalidate z odpowiednim czasem odświeżania. Przykładowo treść wpisu blogowego, opis usługi albo lista kategorii nie muszą być pobierane od nowa przy każdym żądaniu. W wielu przypadkach wystarczy odświeżenie co kilka minut, godzin albo dopiero po zmianie w CMS.
Jeżeli zmiany muszą być widoczne od razu po edycji, można użyć rewalidacji na żądanie, na przykład revalidateTag lub revalidatePath. Dzięki temu po zapisaniu treści w CMS można odświeżyć tylko konkretny fragment aplikacji, zamiast przebudowywać całą stronę.
Trzeba jednak uważać na dane dynamiczne. Jedno niepotrzebne użycie no-store może wyłączyć cache dla całej trasy. Dlatego warto oddzielać dane statyczne od tych, które rzeczywiście muszą być pobierane za każdym razem.
Pomiar Core Web Vitals i analiza bundla
Optymalizacja bez pomiarów łatwo zamienia się w zgadywanie. Dlatego warto regularnie sprawdzać, co faktycznie spowalnia stronę i które elementy mają największy wpływ na użytkowników.
Podstawą są metryki Core Web Vitals. LCP pokazuje, jak szybko ładuje się największy widoczny element strony. INP mierzy responsywność strony po interakcji użytkownika. CLS informuje, czy elementy strony przesuwają się podczas ładowania.
Warto mierzyć te dane nie tylko w narzędziach testowych, takich jak Lighthouse, ale także na produkcji, na podstawie realnych wizyt użytkowników. Wyniki laboratoryjne są pomocne, ale nie zawsze pokazują pełny obraz. Użytkownicy korzystają z różnych urządzeń, sieci i przeglądarek, dlatego dane z prawdziwego ruchu są szczególnie ważne.
Po stronie kodu pomocny będzie @next/bundle-analyzer. To narzędzie pokazuje, które biblioteki i moduły zajmują najwięcej miejsca w paczce wysyłanej do przeglądarki. Częstym problemem są ciężkie biblioteki dat, ikon, wykresów lub edytorów ładowane w całości, mimo że aplikacja używa tylko niewielkiej części ich funkcji.
W wielu przypadkach wystarczy zmienić sposób importu, zastąpić bibliotekę lżejszą alternatywą albo ładować dany komponent dynamicznie. Takie zmiany mogą realnie skrócić czas ładowania strony i poprawić komfort korzystania z aplikacji.
Optymalizacja Next.js jako proces, nie jednorazowe działanie
Optymalizacja aplikacji w Next.js nie polega na jednej zmianie, ale na serii świadomych decyzji. Najpierw warto ograniczyć pracę serwera i ilość JavaScriptu wysyłanego do przeglądarki. Następnie trzeba zadbać o obrazy, czcionki, cache danych oraz sposób ładowania cięższych komponentów.
Najlepsze efekty daje podejście oparte na pomiarach. Zamiast poprawiać wszystko naraz, warto sprawdzić, które elementy rzeczywiście spowalniają stronę i zacząć od tych, które mają największy wpływ na użytkowników. Dzięki temu aplikacja może działać szybciej, stabilniej i lepiej odpowiadać na potrzeby osób korzystających ze strony.
Sprawdźmy Twoją stronę - wyślij adres WWW
Umów krótkie konsultacje SEO

