StriveLab
Strony internetowe
Usługi
RealizacjeO mnieBlogPorozmawiajmy
PL
EN
StriveLab
Strony internetowe
Usługi
RealizacjeO mnieBlogPorozmawiajmy
PL
EN

Next.js

Elastyczne i wydajne narzędzia dla biznesu, które dotrzymają kroku Twojemu rozwojowi.

React

Połączenie intuicyjności z wydajnością, które zapewnia bezproblemową skalowalność kodu.

Astro

Ultraszybkie projekty, łączące lekkość ze skalowalnością.

Doradztwo produktowe

Połączenie perspektywy produktu, developera i marketingu w jednym miejscu

QA & Automation

Testy automatyczne komponentów i E2E w oparciu o Cypress.

SEO & Performance

Audyt techniczny i optymalizacja pod kątem SEO i GEO.

RealizacjeO mnieBlog
Porozmawiajmy
PL
EN

Nowoczesne strony internetowe dla firm, które myślą odważnie.

Przewiń do góry

Nazwa

StriveLab Maciej Sala

NIP

6772218995

REGON

524008527

E-mail

contact@strivelab.pl

Usługi główne
  • Tworzenie stron internetowych
  • Strony internetowe Next.js
  • Strony internetowe Astro
  • Strony internetowe React
Inne usługi
  • Usługi
  • SEO & Performance Sprint
  • QA & Stabilizacja
  • Konsultacje Product / Delivery
  • Aplikacje webowe Next.js
  • Współpraca ciągła
Strony
  • O mnie
  • Usługi
  • Realizacje
  • Blog

© 2026 StriveLab.pl

Polityka prywatności
AstroServer IslandsSSR

Server Islands w Astro — dynamiczne fragmenty na statycznej stronie

Server Islands w Astro pozwalają łączyć szybkość SSG z dynamiką SSR. Jak działa server:defer, kiedy używać, jakie są ograniczenia i jak zaimplementować personalizację bez utraty wydajności.

OpublikujLinkedInFacebookWyślij
Autor
Maciej Sala
Opublikowano
1 maja 2026 16:31
Czytanie
7 min czytania
Aktualizacja
30 kwietnia 2026 19:50

W skrócie

  • Server Islands pozwalają dołożyć dynamiczny fragment bez rezygnowania z cache'owania całej strony. - server:defer tworzy fragment renderowany osobno na serwerze i pobierany po załadowaniu głównego HTML-a. - Fallback, czyli stan zastępczy, jest częścią UX, bo użytkownik widzi go zanim wyspa wróci z serwera. - Propsy do Server Islands muszą być serializowalne; funkcje i cykliczne obiekty odpadają.

Statyczne strony są szybkie, tanie w utrzymaniu i świetnie nadają się do cache'owania na CDN. Problem zaczyna się dopiero wtedy, gdy w tej statycznej stronie pojawia się jeden mały element, który musi być świeży dla każdego użytkownika: avatar po zalogowaniu, licznik komentarzy, cena przeliczona po aktualnym kursie albo rekomendacje dopasowane do bieżącej sesji.

Klasyczna reakcja brzmi: „skoro jest dynamika, cała strona musi przejść na SSR”. Tylko że wtedy tracisz największą zaletę Astro: gotowy HTML, który można szybko podać z CDN bez uruchamiania serwera dla każdego wejścia. Server Islands w Astro to komponenty renderowane na serwerze w osobnym żądaniu, po wysłaniu głównego HTML-a strony. rozwiązują ten problem bardziej precyzyjnie. Statyczna część strony zostaje statyczna, a tylko wybrany fragment jest renderowany na żądanie.

Czym są Server Islands

Server Island to komponent, który renderuje się na serwerze, ale osobno od głównej strony. Pierwsza odpowiedź HTTP zawiera statyczną stronę z miejscem zastępczym tam, gdzie później pojawi się wyspa. Dopiero kolejne żądanie, wykonane automatycznie przez mały skrypt dodany przez Astro, pobiera wyrenderowaną zawartość wyspy i podmienia placeholder.

Kluczowa różnica względem dyrektyw client:* jest prosta: Server Island nie renderuje się w przeglądarce. Jej treść powstaje na serwerze, więc może sięgać do bazy danych, używać sekretów, cookies i sesji — dokładnie tak jak zwykły SSR. Różnica polega na tym, że nie blokuje głównej odpowiedzi strony.

Kiedy Server Islands wygrywają

Scenariusz 1: strona produktu e-commerce. Większość treści (opis, galeria, specyfikacja, recenzje) jest statyczna i zmienia się rzadko. Jeden fragment dynamiczny — stan magazynu — musi być aktualny. Bez Server Islands albo cała strona jest SSR (wolno, drogo), albo pokazujesz nieaktualny stan.

Scenariusz 2: blog z avatarem zalogowanego użytkownika. Sam artykuł jest statyczny i trzymany w cache. Avatar i menu użytkownika w nagłówku muszą być dynamiczne.

Scenariusz 3: personalizowane rekomendacje pod artykułem. Treść artykułu się nie zmienia. Sekcja „Polecamy dla Ciebie” może jednak wyglądać inaczej dla każdego użytkownika.

W każdym z tych przypadków Server Islands pozwalają zachować Cache-Control: public, max-age=3600 dla głównej strony, a dynamiczne fragmenty obsłużyć osobnym żądaniem.

Podstawowa konfiguracja

Server Islands wymagają adaptera SSR. W Astro 6 możesz użyć dowolnego — Node, Vercel, Netlify, Cloudflare:

Code
npx astro add cloudflare
# lub
npx astro add node

Potem oznaczasz komponent dyrektywą server:defer:

Code
---
// src/pages/blog/[slug].astro
import BlogPost from '../../components/BlogPost.astro';
import UserAvatar from '../../components/UserAvatar.astro';
import RelatedPosts from '../../components/RelatedPosts.astro';
---
 
<main>
  <header>
    <nav>
      <!-- Statyczne linki -->
      <a href="/">Home</a>
      <a href="/blog">Blog</a>
 
      <!-- Server Island - personalizowany avatar -->
      <UserAvatar server:defer>
        <div slot="fallback" class="avatar-placeholder">
          <!-- Generyczny awatar pokazany, dopóki dynamiczny się nie załaduje -->
        </div>
      </UserAvatar>
    </nav>
  </header>
 
  <!-- Główna treść statyczna -->
  <BlogPost />
 
  <!-- Server Island - rekomendacje -->
  <RelatedPosts server:defer>
    <div slot="fallback">Ładowanie rekomendacji...</div>
  </RelatedPosts>
</main>

A sam komponent wyspy:

Code
---
// src/components/UserAvatar.astro
const sessionCookie = Astro.cookies.get('session');
const userId = sessionCookie ? await validateSession(sessionCookie.value) : null;
 
if (!userId) {
  // Użytkownik niezalogowany
  return Astro.redirect('/login');
}
 
const user = await getUserById(userId);
---
 
<div class="user-avatar">
  <img src={user.avatar} alt={user.name} />
  <span>{user.name}</span>
  <a href="/logout">Wyloguj</a>
</div>

Wewnątrz wyspy masz pełen dostęp do Astro.cookies, Astro.request, baz danych i sekretów środowiskowych — wszystkiego, co daje SSR. Całość wykonuje się jednak w osobnym żądaniu, więc główna strona nadal może być agresywnie cache'owana.

Fallback, czyli stan zastępczy

slot="fallback" nie jest kosmetyką. To element, który realnie wpływa na UX i Core Web Vitals. Bez fallbacku użytkownik widzi przez chwilę pustą przestrzeń, a potem zawartość wyspy pojawia się nagle. Efekt to skok layoutu, czyli CLS, którego Google nie lubi.

Zasada kciuka: fallback powinien mieć ten sam rozmiar co finalna zawartość wyspy:

Code
<UserAvatar server:defer>
  <div slot="fallback" style="width: 40px; height: 40px; border-radius: 50%; background: #e5e7eb;">
    <!-- Miejsce zastępcze okrągłe jak awatar, ten sam rozmiar -->
  </div>
</UserAvatar>

Dla ekranów szkieletowych:

Code
<RelatedPosts server:defer>
  <div slot="fallback" class="related-skeleton">
    <div class="skeleton-card" />
    <div class="skeleton-card" />
    <div class="skeleton-card" />
  </div>
</RelatedPosts>

CSS do skeletonu (Tailwind):

Code
.skeleton-card {
  @apply h-48 animate-pulse rounded-lg bg-gray-200;
}

Użytkownik widzi, że coś się ładuje, layout zostaje stabilny, a CLS nie wymyka się spod kontroli.

Jak działa to technicznie

Kiedy Astro renderuje stronę z Server Islands:

  1. Każda wyspa server:defer jest wydzielona do osobnej, wewnętrznej ścieżki /_server-islands/{name}.
  2. W głównym HTML-u jest wstawiony placeholder i mały skrypt, który po załadowaniu strony robi fetch() do endpointu wyspy.
  3. Odpowiedź z wyspy, czyli jej HTML, jest podmieniana w miejscu placeholdera.

Dla przeglądarki wygląda to jak:

Code
1. GET /blog/my-post               → HTML + fallback + skrypt
2. GET /_server-islands/UserAvatar → HTML wyspy
3. JavaScript podmienia fallback

Propsy przekazywane do wyspy są szyfrowane kluczem generowanym podczas buildu i przekazywane w URL-u jako parametr. Dzięki temu:

  • Możesz bezpiecznie przekazywać dane użytkownika bez ryzyka prostej podmiany wartości.
  • Astro wspiera cache'owanie przez Cache-Control — jeśli propsy są te same, Cloudflare czy CDN mogą zcache'ować odpowiedź wyspy.

Ograniczenie: URL nie może przekroczyć 2048 bajtów. Jeśli propsy są zbyt duże, Astro przełącza się na POST, którego nie da się tak łatwo cache'ować. Wniosek praktyczny: przekazuj do wyspy tylko minimalne ID, a resztę danych pobieraj wewnątrz.

Server Islands a Partial Prerendering w Next.js

Wygląda podobnie? Next.js 15+ ma Partial Prerendering (PPR) + streaming z Suspense, co na pierwszy rzut oka rozwiązuje ten sam problem. Ale mechanika jest inna:

AspektAstro Server IslandsNext.js PPR
Model mentalnyWyspa jako osobny endpointGranica Suspense w obrębie jednej strony
DostawaDrugie żądanie HTTPStreaming w pierwszym żądaniu
Runtime klientaMały skrypt do pobrania i podmiany HTML-aRuntime Reacta + logika streamingu
Cache'owanieOsobne reguły Cache-Control dla wyspyCache całości lub nic (granularność ograniczona)
Kiedy wygrywaRzadko zmieniane strony + drobne dynamiczne daneAplikacje z dużą ilością SSR + wyspowe dane

PPR jest mocniej zintegrowany z ekosystemem Reacta i zwykle lepiej pasuje do aplikacji. Server Islands są prostsze koncepcyjnie i bardzo dobrze pasują do stron zorientowanych na treść. Nie ma tu jednego zwycięzcy — są dwa różne sposoby rozwiązania tego samego problemu. Ogólne porównanie obu frameworków opisuję w osobnym artykule.

Praktyczny przykład — licznik komentarzy

Weźmy prosty przykład: blog z ponad setką artykułów. Każdy artykuł jest generowany statycznie i trzymany w cache CDN przez godzinę. Do tego chcemy pokazać aktualny licznik komentarzy.

Bez Server Islands wrzucasz fetch() do API komentarzy bezpośrednio w szablonie. Strona staje się SSR, trudniej ją cache'ować, bo liczba komentarzy stale się zmienia, a odpowiedź robi się wolniejsza.

Z Server Islands:

Code
---
// src/pages/blog/[slug].astro
import BlogPost from '../../components/BlogPost.astro';
import CommentsCount from '../../components/CommentsCount.astro';
 
const { post } = Astro.props;
---
 
<BlogPost post={post}>
  <aside class="post-meta">
    <span>
      Komentarze:
      <CommentsCount server:defer postId={post.id}>
        <span slot="fallback" class="inline-block w-8 h-4 bg-gray-200 rounded animate-pulse" />
      </CommentsCount>
    </span>
  </aside>
</BlogPost>
Code
---
// src/components/CommentsCount.astro
const { postId } = Astro.props;
const response = await fetch(`${import.meta.env.API_URL}/comments/count?postId=${postId}`);
const { count } = await response.json();
---
 
<strong>{count}</strong>

Efekt: artykuł nadal może leżeć w cache CDN przez godzinę, a licznik komentarzy odświeża się przy każdym wejściu albo korzysta z krótszego cache ustawionego bezpośrednio dla wyspy.

Ograniczenia i pułapki

1. Propsy muszą być serializowalne. Nie przekażesz funkcji, klas ani komponentów do Server Island. Tylko prymitywy, tablice, obiekty JSON, daty.

2. Astro.url wewnątrz wyspy wskazuje ścieżkę wyspy, nie strony. Wewnątrz komponentu Astro.url zwróci /_server-islands/CommentsCount?..., nie /blog/my-post. Jeśli potrzebujesz URL strony, czytaj nagłówek Referer:

Code
---
const referer = Astro.request.headers.get('referer');
const pageUrl = referer ? new URL(referer) : null;
---

3. Wyspa nie widzi zmiennych kontekstu z głównego renderu. Każda wyspa renderuje się w izolowanym żądaniu. Jeśli w głównej stronie ustawisz zmienną, wyspa jej nie zobaczy — musisz przekazać przez propsy.

4. Cache i prywatne dane. Jeśli wyspa zwraca dane zależne od użytkownika, takie jak avatar albo personalizacja, musisz ustawić Cache-Control: private lub no-store, żeby CDN nie podał cudzych danych kolejnej osobie.

Cache, prywatność i stan zastępczy

Server Island jest świetnym narzędziem tylko wtedy, gdy świadomie rozdzielisz trzy warstwy: główny HTML, dynamiczny endpoint wyspy i stan zastępczy widoczny przed podmianą.

  • Główna strona może mieć agresywny cache publiczny, bo nie zawiera prywatnych danych.
  • Wyspa z danymi użytkownika powinna mieć Cache-Control: private albo no-store.
  • Wyspa z danymi publicznymi, ale często zmiennymi, może mieć krótki cache, np. s-maxage=60.
  • Do propsów przekazuj identyfikatory i małe wartości, a nie pełne rekordy z bazy.
  • Stan zastępczy powinien zajmować tyle samo miejsca co finalna treść, żeby nie generować CLS.
Uwaga

Treści kluczowe dla SEO renderuj w głównym HTML-u. Server Islands traktuj jako warstwę świeżości, personalizacji albo pomocniczych danych, nie jako miejsce na główną odpowiedź artykułu.

Wydajność — czy to realnie szybsze?

Krótko: tak, ale nie zawsze. Server Islands wygrywają, kiedy:

  • Większość strony jest statyczna i może być agresywnie cache'owana.
  • Dynamiczny fragment jest mały (klient nie musi długo czekać na drugą odpowiedź).
  • Cache'owanie na CDN daje realny zysk (dużo odwiedzin tej samej strony).

Nie wygrywają, kiedy:

  • Cała strona i tak musi być SSR (np. dashboard).
  • Dynamiczny fragment jest duży (np. cała lista 50 produktów) — wtedy drugie żądanie staje się wąskim gardłem.
  • Strona ma ruch o niskiej częstotliwości (cache się nie opłaca).

Podsumowanie

Server Islands to elegancka odpowiedź na problem, który wraca w wielu projektach: większość strony może być statyczna, ale jeden fragment musi pozostać świeży. Zamiast wybierać między „wszystko SSG” a „wszystko SSR”, dostajesz kontrolę na poziomie konkretnego komponentu: statyczna powłoka trafia do cache CDN, a dynamiczne fragmenty są obsługiwane osobnym żądaniem.

Jeśli masz stronę w Astro, która powoli dryfuje w stronę SSR, bo dochodzą kolejne dynamiczne elementy, Server Islands mogą pomóc zachować statyczny fundament bez rezygnowania z personalizacji. Jeśli potrzebujesz pomocy w architekturze strony w Astro z mieszanymi wymaganiami statyki i dynamiki, napisz do mnie.

Często zadawane pytania

Nie. Server Islands działają z każdym adapterem SSR — Node.js, Vercel, Netlify, Cloudflare, Deno. Potrzebujesz adaptera obsługującego renderowanie na żądanie (on-demand rendering), ale nie konkretnej platformy.

Pracuję z tym zawodowo.

Jeśli chcesz przełożyć ten temat na lepszą architekturę frontendu, uporządkować React lub Next.js i podnieść jakość pracy zespołu, skontaktuj się ze mną. Pomagam zamieniać wiedzę z artykułów w praktyczne decyzje technologiczne.

Skontaktuj się ze mną
Maciej Sala

O autorze

Maciej Sala

Maciej Sala — project manager i frontendowiec z doświadczeniem w marketingu internetowym. Na co dzień pracuję z Reactem, Next.js i TypeScriptem, łącząc perspektywę produktową z praktycznym podejściem do kodu. Przez kilka lat związany z branżą gier wideo jako project manager i game designer.

Absolwent historii na Uniwersytecie Jagiellońskim i studiów podyplomowych z marketingu internetowego na Akademii Górniczo-Hutniczej w Krakowie. Poza pracą trenuje na siłowni, maluje figurki i realizuje własne projekty.

Moje artykułyWięcej o mnie

Seria

Astro w praktyce 2026
  1. 1Astro 6 — przewodnik po nowościach: Cloudflare Workers, Live Content Collections, Fonts API i CSP
  2. 2Architektura wysp w Astro — czym są wyspy i dlaczego zero JS domyślnie zmienia zasady gry
  3. 3SEO w Astro — Core Web Vitals, dane uporządkowane i techniczny fundament rankingu w 2026
  4. 4Migracja bloga z WordPress na Astro — eksport treści, przekierowania 301 i zachowanie pozycji w Google

Spis treści

11 sekcji · 11 min

  • Czym są Server Islands1 min
  • Kiedy Server Islands wygrywają1 min
  • Podstawowa konfiguracja1 min
  • Fallback, czyli stan zastępczy1 min
  • Jak działa to technicznie1 min
  • Server Islands a Partial Prerendering w Next.js1 min
  • Praktyczny przykład — licznik komentarzy1 min
  • Ograniczenia i pułapki1 min
  • Cache, prywatność i stan zastępczy1 min
  • Wydajność — czy to realnie szybsze?1 min
  • Podsumowanie1 min

Biblioteka wiedzy

Czytaj dalej

Zobacz więcej wpisów
SEO w Astro — Core Web Vitals, dane uporządkowane i techniczny fundament rankingu w 2026

SEO w Astro — Core Web Vitals, dane uporządkowane i techniczny fundament rankingu w 2026

Jak zbudować stronę w Astro, która dominuje w SEO — Core Web Vitals, sitemap, robots.txt, metadane, dane uporządkowane i GEO/AEO. Przewodnik techniczny z konkretnymi implementacjami.

Maciej Sala

Maciej Sala

Founder Strivelab

1 maja 2026
Migracja bloga z WordPress na Astro — eksport treści, przekierowania 301 i zachowanie pozycji w Google

Migracja bloga z WordPress na Astro — eksport treści, przekierowania 301 i zachowanie pozycji w Google

Kompletny przewodnik po migracji bloga z WordPress na Astro. Eksport przez REST API i WXR, mapowanie URL, przekierowania 301, migracja obrazów do astro:assets i monitoring pozycji w Google.

Maciej Sala

Maciej Sala

Founder Strivelab

1 maja 2026
Architektura wysp w Astro — czym są wyspy i dlaczego zero JS domyślnie zmienia zasady gry

Architektura wysp w Astro — czym są wyspy i dlaczego zero JS domyślnie zmienia zasady gry

Architektura wysp to fundament Astro. Wyjaśniam, czym są wyspy, jak działa selektywna hydracja, kiedy daje realną przewagę i gdzie jest jej granica — z przykładami kodu i benchmarkami.

Maciej Sala

Maciej Sala

Founder Strivelab

1 maja 2026