Next.js to potężne narzędzie, ale niewłaściwie użyte potrafi zniszczyć wyniki sprzedażowe
Od kilku lat Next.js króluje w projektach e-commerce – i słusznie. Łączy wydajność statycznych stron z elastycznością aplikacji single-page, oferując SEO, szybkie ładowanie i świetne UX. Ale widzę coraz więcej sklepów, które po migracji na Next.js… tracą konwersję. Nie chodzi o sam framework, tylko o błędy w architekturze, które popełniają zespoły deweloperskie (często w dobrej wierze).
W tym artykule pokażę trzy najczęstsze pułapki, które kosztują realną sprzedaż. Opieram się na obserwacjach z projektów, które prowadziłem – zarówno w JurskiTech, jak i wcześniej.
1. Nadmiarowa strategia renderowania – Server-Side Rendering (SSR) wszędzie
Next.js daje trzy tryby renderowania: SSG (Static Site Generation), SSR (Server-Side Rendering) i ISR (Incremental Static Regeneration). Najpopularniejszym wyborem dla e-commerce jest SSR – każda strona generowana na żądanie serwera. Brzmi bezpiecznie, ale ma ukryty koszt: czas odpowiedzi.
Przykład z życia: Klient – sklep z odzieżą premium, ~5000 produktów. Zdecydowali się na SSR dla wszystkich stron produktowych, bo „lepiej pokazywać aktualne ceny i stany magazynowe”. Po wdrożeniu zauważyli spadek konwersji o 8%. Powód? Średni czas odpowiedzi serwera dla strony produktu wynosił 1,2 sekundy – niby niewiele, ale dla użytkownika sumaryczny czas do interakcji skoczył do 3,5 sekundy.
Dlaczego tak się dzieje? SSR wymaga wykonania kodu po stronie serwera przy każdym żądaniu. Jeśli backend (np. API magazynowe) jest wolny, cały łańcuch się opóźnia. A w e-commerce każda dodatkowa sekunda to nawet 7% spadku konwersji (dane Amazon).
Jak to naprawić? Zastosuj hybrydowe podejście:
- Strony kategorii i główne – SSG z ISR (odświeżanie co 5-10 minut dla zmian asortymentu).
- Strony produktowe – SSR tylko jeśli dane zmieniają się dynamicznie (np. dostępność w czasie rzeczywistym). W przeciwnym razie ISR z krótkim interwałem.
- Fragmenty dynamiczne (cena, stan magazynowy) – Client-side fetch po załadowaniu statycznej treści. Dzięki temu użytkownik widzi od razu szkielet strony, a dane doczytują się bez blokowania.
Efekt: Czas do pierwszego malowania skrócony o 40%, konwersja wróciła do normy, a nawet wzrosła o 3%.
2. Przeładowanie JavaScript – bundle, który niszczy Core Web Vitals
Next.js domyślnie dostarcza sporo kodu – framework, biblioteki, routing. Jeśli dodasz do tego własne moduły, zwłaszcza ciężkie biblioteki UI czy frameworki CSS-in-JS (jak styled-components), bundle potrafi urosnąć do 500 kB i więcej. W efekcie – słaby First Input Delay (FID) i ogólna ociężałość.
Realny przypadek: Sklep z elektroniką używał Next.js z Emotion (CSS-in-JS) i React Query. Bundle główny – 620 kB. Po wdrożeniu Google Core Web Vitals – ocena „Poor” dla LCP i FID. Konwersja spadła o 5% w ciągu miesiąca.
Co poszło nie tak? Deweloperzy nie skonfigurowali code splittingu – każda strona ładowała cały bundle, chociaż 70% kodu było zbędne na starcie. Dodatkowo, Emotion generuje klasy CSS dynamicznie, co powoduje re-renderowanie i blokuje główny wątek.
Jak uniknąć?
- Używaj natywnych modułów CSS lub Tailwind – eliminujesz narzut runtime’u.
- Wdróż dynamiczny import dla komponentów niewidocznych na pierwszym ekranie (np. koszyk, rekomendacje).
- Zintegruj next/dynamic – ładuj komponenty tylko gdy zajdzie potrzeba.
- Regularnie analizuj bundle za pomocą @next/bundle-analyzer. Utrzymuj rozmiar poniżej 200 kB dla głównego chunka.
Efekt: Bundle spadł do 180 kB, LCP poprawiło się z 3.2 s do 1.8 s. Sklep odzyskał 4% konwersji.
3. Niewłaściwe zarządzanie stanem – przynoszenie zewnętrznego stanu globalnego
Next.js działa w dwóch środowiskach: serwer i klient. To, co działa w klasowym React, może nie działać w Next.js. Częsty błąd: używanie Redux lub Zustand do zarządzania całym stanem aplikacji, nawet dla danych, które powinny być serwerowe.
Przykład: Sklep spożywczy – lista produktów była przechowywana w Reduxie. Każda nawigacja powodowała pobranie danych z API i zapisanie w store. Problem: przy przeładowaniu strony Redux resetował stan, a dane trzeba było pobierać od nowa. Użytkownicy często widzieli pustą stronę przez 2-3 sekundy. Konwersja spadła o 10%.
Dlaczego to złe? Redux jest świetny dla klienta, ale w Next.js należy oddzielić dane serwerowe od stanu UI. Używanie globalnego store’a do danych produktowych prowadzi do duplikacji, niepotrzebnych zapytań i opóźnień.
Poprawne podejście:
- Serwerowe źródło prawdy – pobieraj dane na serwerze za pomocą
getServerSidePropslubgetStaticPropsi przekaż jako props. - Stan UI (koszyk, preferencje) – lokalny stan w komponencie lub lekki store jak Zustand tylko dla interakcji klienckich.
- Dla danych współdzielonych między komponentami – React Context, ale tylko dla prostych rzeczy (np. motyw).
Efekt: Po refaktoryzacji – usunięto Redux, dane serwerowe przychodzą jako props, lokalny stan tylko dla koszyka. Czas ładowania strony skrócił się o 50%, konwersja wzrosła o 8%.
Podsumowanie – architektura ma znaczenie
Next.js to nie jest magiczne pudełko. Błędy w strategii renderowania, przeładowany bundle i niewłaściwe zarządzanie stanem to trzy grzechy główne, które widzę w większości sklepów e-commerce migrujących na ten framework. Każdy z nich kosztuje konwersję – realne pieniądze.
Jeśli planujesz przebudowę swojego sklepu lub właśnie przechodzisz na Next.js, zadbaj o te trzy obszary. Albo jeszcze lepiej – poproś kogoś z doświadczeniem, żeby rzucił okiem na architekturę. Czasem jeden dzień audytu oszczędza miesiące przepisywania kodu.
A Ty? Zauważyłeś podobne problemy u siebie? Daj znać – chętnie wymienię się doświadczeniami.


