SEO w Astro

Astro jest jednym z najmocniejszych frameworków do SEO — strony są domyślnie prerenderowane do statycznego HTML-u i wysyłają JavaScript tylko tam, gdzie o to poprosisz, z dobrymi wynikami Core Web Vitals. Ustawienia domyślne nie są jednak gwarancjami, a Astro nie tworzy za Ciebie tagów meta, mapy witryny ani adresów kanonicznych. Oto jak prowadzę własną witrynę Astro i jak poprawnie ustawić jej architekturę.

Opublikowano po raz pierwszy: 26 cze 2026 · Ostatnia aktualizacja: 8 sie 2026 · Advanced
Języki

Astro jest jednym z najlepszych wyborów frameworka do SEO, ponieważ domyślnie prerenderuje strony do statycznego HTML-u — treść znajduje się w surowym HTML-u przy pierwszym crawlowaniu, bez kolejki renderowania, na którą trzeba czekać dla tej trasy. Wyspy hydratyzują tylko komponenty oznaczone dyrektywą klienta, więc większość strony jest wysyłana bez własnego JS hydratacji (Astro nadal może dodać skrypty strony i JS routera w innych miejscach) — nic z tego samo w sobie nie gwarantuje indeksowalności, indeksowania ani rankingów, dlatego sprawdzaj wdrożone trasy. Witryny Astro osiągają także dobre wyniki Core Web Vitals. Minusem jest to, że Astro generuje czysty HTML, ale nie tworzy tagów meta, adresów kanonicznych, mapy witryny ani danych strukturalnych — to celowe kroki budowania, a odkrywanie mapy witryny obejmuje statycznie generowane trasy, więc adresy dostępne wyłącznie w runtime wymagają jawnej obsługi. Server Islands (wymagające adaptera) i View Transitions są bezpieczne dla SEO, gdy rozumiesz, co crawlery faktycznie pobierają. Prowadzę patrickstox.com na Astro, więc to stos, z którego naprawdę korzystam.

TL;DR — Astro jest architektonicznie dobrze przygotowane do SEO: strony i endpointy są domyślnie prerenderowane do statycznego HTML-u, więc dla tej treści nie trzeba czekać na falę kolejki renderowania — ale to ustawienie domyślne, a nie uniwersalna gwarancja, a sam statyczny lub serwerowy HTML nie dowodzi indeksowalności, indeksowania, rankingów ani Core Web Vitals produkcyjnych adresów URL. Architektura Islands nawadnia tylko komponenty oznaczone dyrektywą client:* — pozostała część wysyła HTML bez własnego JavaScriptu hydratacji, choć skrypty strony, inne wyspy i usprawnienia routera mogą dodać JavaScript w innych miejscach strony. Astro nie generuje automatycznie tagów meta, kanonicznych adresów, map witryny ani danych strukturalnych — skonfiguruj je jawnie, najlepiej poddając walidacji przez Content Collections + Zod. Server Islands (wymagające adaptera) serwują statyczną powłokę z treścią zastępczą w dokumencie początkowym, a później niezależnie pobierają odroczoną treść — sprawdź, co faktycznie pobiera dany crawler, zamiast zakładać. View Transitions używa history.pushState i jest bezpieczne dla SEO; Google crawluje bazowe strony MPA normalnie. Prowadzę patrickstox.com na Astro, a poniższe funkcje to te, których faktycznie używam — sprawdzone na wdrożonej witrynie, a nie tylko w lokalnym środowisku.

Evidence for this claim Astro prerenders pages as static HTML by default and only sends client JavaScript for explicitly hydrated components. Scope: Astro default static output and islands architecture. Confidence: high · Verified: Astro: Why Astro

Dlaczego Astro całkowicie omija problem renderowania JavaScriptu

Cały problem SEO JavaScriptu bierze się z drugiej fali. Google najpierw pobiera surowy HTML, a potem umieszcza stronę w kolejce do renderowania w bezgłowym Chromium — i właśnie ta kolejka jest ryzykiem. Własne dokumenty Google opisują to tak: “Googlebot queues all pages with a 200 HTTP status code for rendering unless a robots meta tag tells Google not to index the page. The page may stay on this queue for a few seconds, but it can take longer than that.” (tłumaczenie) „Googlebot umieszcza każdą stronę z kodem statusu HTTP 200 w kolejce renderowania, chyba że tag robots meta mówi Google, aby nie indeksował strony. Strona może pozostać w tej kolejce kilka sekund, ale może to potrwać dłużej.” W aplikacji SPA renderowanej po stronie klienta treść nie istnieje, dopóki ta fala renderowania się nie odbędzie.

Domyślny tryb wyjściowy Astro jest statyczny: strony i endpointy są prerenderowane do kompletnego pliku HTML w czasie budowania. Dla trasy działającej w tym trybie surowy HTML jest wyrenderowaną stroną. Evidence for this claim Astro uses static output and prerenders routes at build time by default. Scope: Astro default output mode; routes can opt out of prerendering. Confidence: high · Verified: Astro: On-demand rendering Nie ma drugiej fali, na którą trzeba czekać, ponieważ nie zostało już nic do wykonania. Googlebot widzi pełną treść przy pierwszym pobraniu. Jak ujmuje to Joost de Valk (założyciel Yoast): “From an SEO perspective, static HTML on a CDN is a better starting point than most CMSes will ever give you.” (tłumaczenie) „Z perspektywy SEO statyczny HTML na CDN-ie jest lepszym punktem wyjścia, niż kiedykolwiek zapewni większość CMS-ów”.

To jednak ustawienie domyślne, a nie uniwersalna właściwość każdej trasy. Ustaw output: 'server', a domyślny tryb zmieni się na renderowanie na żądanie (więcej na ten temat poniżej); nawet w projekcie domyślnie statycznym adapter pozwala pojedynczej trasie wyłączyć prerenderowanie za pomocą export const prerender = false. Sama architektura niczego tu nie gwarantuje: statyczny lub serwerowy HTML, wyspy i adaptery nie zapewniają automatycznie indeksowalności, indeksowania, rankingów ani Core Web Vitals — zależy to od wdrożonej trasy i konkretnego crawlera, więc sprawdzaj to zamiast zakładać, że framework się tym zajmie.

Pomaga to także crawlerom, które w ogóle nie potrafią renderować. Google mówi wprost, że “not all bots can run JavaScript” (tłumaczenie) „nie każdy bot potrafi uruchomić JavaScript” — i to jest rzeczywistość 2026 roku w przypadku większości crawlerów AI oraz wielu narzędzi zewnętrznych. Wyjście Astro w pierwszej kolejności jako HTML jest czytelne dla każdego z nich tam, gdzie faktycznie zostało prerenderowane, a nie tylko dla Googlebota. (To ten sam punkt, który przedstawiam w SEO dla bezgłowego CMS-a: tryb renderowania jest częścią produktu.)

Architektura Islands: JS tylko tam, gdzie go potrzebujesz

Astro renderuje komponenty do HTML-u i, jak samo mówi, wysyła “just HTML & CSS, stripping out all client-side JavaScript automatically.” (tłumaczenie) „tylko HTML i CSS, automatycznie usuwając cały JavaScript po stronie klienta”. Interaktywność jest opcjonalna. Oznaczasz komponent dyrektywą client:*client:load, client:idle lub client:visible — i tylko ta wyspa jest hydratowana JavaScriptem. Cała reszta pozostaje statycznym HTML-em. Evidence for this claim Astro client directives selectively hydrate interactive islands while other components remain static HTML. Scope: Astro islands and client directives. Confidence: high · Verified: Astro: Islands

Z punktu widzenia SEO jest to niemal idealne. Treść, którą Googlebot musi zaindeksować, to zwykły HTML, a interaktywne widgety nie obciążają go. client:visible jest szczególnie użyteczne: komponent poniżej pierwszego ekranu nie zaczyna hydratacji, dopóki nie pojawi się w polu widzenia, więc nigdy nie blokuje LCP. Koncepcja pochodzi od Jasona Millera (twórcy Preacta), który opisał “rendering HTML pages on the server, and inject[ing] placeholders or slots around highly dynamic regions” (tłumaczenie) „renderowanie stron HTML na serwerze i wstrzykiwanie placeholderów lub slotów wokół wysoce dynamicznych obszarów” na potrzeby selektywnej hydratacji.

Dwie kwestie wymagają precyzji, ponieważ materiały konkurencji często je zacierają:

  • client:only to coś innego. W przeciwieństwie do client:load/client:idle/client:visible komponent client:only całkowicie pomija renderowanie po stronie serwera — na serwerze nie tworzy żadnego HTML-u. Treść indeksowalna umieszczona wyłącznie w komponencie client:only nie znajduje się w dokumencie pobieranym przez Googlebota; istnieje dopiero po hydratacji w przeglądarce. Nie umieszczaj tam głównej treści.
  • To selektywna hydratacja, a nie resumowalność. Astro uruchamia kod klienta każdej wyspy od początku w przeglądarce; nie wznawia stanu wykonania zserializowanego na serwerze tak, jak robi to model resumowalności (na przykład Qwika). W tekstach te pojęcia bywają mieszane — nie oznaczają tego samego.
Evidence for this claim A client:only component skips server rendering, so indexable content placed only inside it cannot be assumed to exist in the initial page HTML. Scope: client and server islands Confidence: high · Verified: Template directives reference

Nawet komponent bez hydratacji nie wyczerpuje obrazu JavaScriptu na stronie. „Zero JS” opisuje jeden komponent bez dyrektywy client:* — Astro nadal może wysłać tagi <script> na poziomie strony, router View Transitions i inne wyspy w innych miejscach tej samej strony. Opisuj to, co wysyłane jest na komponent lub trasę, a nie jako ogólną właściwość całej strony.

Czego Astro NIE robi automatycznie

Astro generuje czysty, semantyczny HTML — i nic więcej z punktu widzenia SEO. Domyślnie nie ma metadanych, kanonicznego adresu, mapy witryny ani danych strukturalnych. Mit, że „Astro jest automatycznie zoptymalizowane pod SEO”, jest właśnie mitem. To Ty odpowiadasz za:

  • Tagi meta (tytuł, opis, Open Graph, Twitter)
  • Adresy kanoniczne
  • Mapę witryny (przez oficjalną integrację)
  • Dane strukturalne / JSON-LD
  • robots.txt

Astro jest najlepszą podstawą, z jakiej korzystałem, ale to podstawa, a nie gotowy dom.

Mapa witryny: @astrojs/sitemap

Zainstaluj ją poleceniem npx astro add sitemap. Integracja crawluje trasy generowane statycznie i w czasie budowania emituje sitemap-index.xml oraz podzielone na fragmenty pliki sitemap-0.xml. Dwie rzeczy często sprawiają problemy:

Evidence for this claim Astro's official sitemap integration generates sitemap files from statically generated routes. Scope: Astro @astrojs/sitemap integration. Confidence: high · Verified: Astro: Sitemap integration
  • Musisz ustawić site: w astro.config.mjs. Bez tego integracja po cichu nie wygeneruje niczego. To najczęstsza przyczyna pytania „gdzie jest moja mapa witryny?”.
  • Musisz samodzielnie dodać wiersz mapy witryny do robots.txt. Astro tego nie robi.

Dla większej kontroli filter() wyklucza trasy (strony podglądu i wersje robocze — dokładnie do tego używam go w tej witrynie), serialize() pozwala ustawić lastmod/changefreq/priority, a opcja i18n emituje wpisy hreflang w mapie witryny. Tak właśnie opisują to aktualne dokumenty @astrojs/sitemap — jeśli korzystasz ze starszej wersji, sprawdź własną instalację, ponieważ zachowanie integracji zmieniało się między głównymi wersjami.

To zakres powoduje najwięcej problemów: mechanizm odkrywania integracji obejmuje trasy wygenerowane statycznie. Jeśli którykolwiek z adresów URL istnieje tylko w czasie działania — trasy serwerowe (output: 'server') albo trasy generowane na żądanie, a nie podczas budowania — nie zakładaj, że znajdzie się w mapie witryny. Dodaj go jawnie przez customPages, a po budowaniu rzeczywiście otwórz sitemap-index.xml, aby potwierdzić obecność. W przypadku trasy, która nie jest statyczna w czasie budowania, nie przyjmuj na wiarę, że „integracja się tym zajmuje”.

Tagi meta i kanoniczne: wzorzec BaseLayout

Astro nie ma specjalnego komponentu <Head> — bezpośrednio kontrolujesz <head> w plikach .astro. Standardowy wzorzec (i ten, którego używam) to pojedynczy BaseLayout.astro, który przyjmuje właściwości title, description i canonicalURL, a następnie zapisuje nagłówek. Ustaw jawnie kanoniczny adres na każdej stronie i zachowaj jego zgodność z og:url. Biblioteka nie jest konieczna, ale społecznościowy pakiet astro-seo (npm) to wygodna otoczka jednego komponentu dla tytułu/opisu/OG/Twittera/kanonicznego adresu, jeśli jej potrzebujesz.

Content Collections jako zabezpieczenie SEO

To niedoceniana funkcja SEO Astro. Content Collections to bezpieczna typowo warstwa treści dla Markdown/MDX/JSON z walidacją schematu Zod. Możesz dzięki temu uczynić title i description polami wymaganymi — a jeśli którejś brakuje, kompilacja kończy się błędem. Nie da się przypadkiem wysłać strony bez tytułu. Funkcje zapytań (getCollection(), getEntry()) generują statyczne strony w czasie budowania, więc po wdrożeniu wyjściem jest zwykły HTML. Ponieważ MDX zachowuje surowy Markdown jako źródło prawdy, pliki te są także czystą treścią źródłową dla crawlerów AI i wzorców w rodzaju llms.txt. Ta witryna jest zbudowana na Content Collections z frontmatterem walidowanym przez Zod.

astro:assets: obrazy zrobione poprawnie (z jedną pułapką)

Komponent <Image /> automatycznie konwertuje obrazy do WebP, ustala wymiary, aby “avoid Cumulative Layout Shift (CLS),” (tłumaczenie) „uniknąć Cumulative Layout Shift (CLS)”, domyślnie ustawia loading="lazy" i wymaga alt — brak alt jest błędem kompilacji. <Picture /> rozszerza to o elementy <source> AVIF/WebP i fallback.

Pułapka: automatyczne loading="lazy" jest nieprawidłowe dla obrazu LCP (zwykle hero). Lazy loading najważniejszego obrazu opóźnia go. W przypadku obrazów powyżej pierwszego ekranu nadpisz ustawienie przez loading="eager" i fetchpriority="high". Obrazy zdalne potrzebują jawnych wartości width i height.

Server Islands: co faktycznie widzą crawlery

Server Islands (Astro 4.12+) to funkcja, którą większość poradników konkurencji opisuje błędnie. Przy server:defer komponent renderuje się na serwerze niezależnie od głównej strony. Statyczna powłoka jest wysyłana od razu; zgodnie z dokumentami Astro: “Your page will be rendered immediately with any specified fallback content as a placeholder. Then, the component’s own contents are fetched on the client and displayed when available.” (tłumaczenie) „Twoja strona od razu zostanie wyrenderowana z określoną treścią zastępczą jako placeholderem. Następnie własna treść komponentu zostanie pobrana po stronie klienta i wyświetlona, gdy będzie dostępna”.

Dwie kwestie wymagają precyzji. Po pierwsze, Server Islands wymagają adaptera — jest to funkcja na żądanie, a nie coś, co czysto statyczne budowanie tworzy samo z siebie. Po drugie, sekwencja wygląda tak: dokument początkowy zawiera skonfigurowaną treść zastępczą, a rzeczywista treść wyspy jest osobnym, niezależnym żądaniem pobieranym po załadowaniu strony z własnego endpointu. To twarda granica tego, co zawiera pierwszy dokument — bez bezpośredniego testowania własnych wdrożonych adresów URL nie uogólniałbym na tej podstawie tego, co później robi każdy konkretny crawler.

Konsekwencja SEO jest konkretna: statyczny HTML odczytywany przez crawler przy pierwszym pobraniu zawiera treść zastępczą, a nie odroczoną treść wyspy. To idealne rozwiązanie dla tego, do czego służą Server Islands — spersonalizowanych, zależnych od sesji elementów (stan logowania, licznik koszyka, rekomendacje), których i tak nie należy buforować ani indeksować. Nie sprawdza się w przypadku głównej treści indeksowalnej. Wszystko, co ma zajmować pozycje, umieść w głównym szablonie Astro, a Server Islands zostaw na otaczające je elementy dynamiczne.

Tryby wyjścia: statyczny i serwerowy oraz nadpisanie dla pojedynczej trasy

Domyślny tryb wyjściowy Astro to static — strony i endpointy są prerenderowane do HTML-u w czasie budowania. Ustaw output: 'server' w astro.config.mjs, a domyślny tryb zmieni się na renderowanie na żądanie: strony będą renderować się przy każdym żądaniu (z adapterem), co przydaje się w przypadku uwierzytelniania, danych w czasie rzeczywistym lub personalizacji wykraczającej poza możliwości Server Islands. W obu trybach możesz nadpisać domyślne ustawienie dla trasy: w projekcie domyślnie statycznym export const prerender = false włącza renderowanie na żądanie, a w projekcie domyślnie serwerowym export const prerender = true przywraca prerenderowanie podczas budowania. Stwierdzenie „moja witryna jest statyczna” lub „moja witryna używa SSR” rzadko jest prawdziwe dla każdej trasy — sprawdź ustawienie trasy, a nie tylko konfigurację najwyższego poziomu.

Evidence for this claim Astro uses static output and prerenders routes at build time by default. Scope: Astro default output mode; routes can opt out of prerendering. Confidence: high · Verified: Astro: On-demand rendering

Z czysto SEO-wego punktu widzenia prerenderowany i generowany na żądanie HTML są równoważne — oba dostarczają crawlerowi kompletny HTML przy pierwszym żądaniu, gdy faktycznie potwierdzisz, że trasa zwraca 200 z pełnym oznaczeniem. Trasy generowane na żądanie mogą strumieniować HTML, a wolne dane lub warunki sieciowe mogą opóźniać późniejsze fragmenty, więc strumieniowana odpowiedź nie jest automatycznym dowodem, że dotarła cała treść — sprawdź to, nie zakładaj. Prawdziwa różnica między trybami jest operacyjna: prerenderowana treść pozostaje stała do następnego budowania (lub osobno skonfigurowanego odświeżenia w czasie działania) i jest serwowana prosto z brzegu CDN; treść na żądanie jest zawsze aktualna, ale zależy od zdrowego działania adaptera i środowiska uruchomieniowego na produkcji. Nie traktuj tego jako decyzji SEO — wybierz tryb według świeżości danych i operacji, a następnie zweryfikuj wdrożone trasy, statusy, przekierowania i nagłówki odpowiedzi, zamiast ekstrapolować z lokalnego środowiska.

View Transitions: bezpieczne dla SEO mimo wrażenia SPA

Astro <ClientRouter /> (wcześniej <ViewTransitions />) zapewnia miękką nawigację w stylu SPA za pomocą przeglądarkowego API View Transitions i History API. Kluczowy fakt: nawiguje przez history.pushState, dokładnie tak, jak Google zaleca w nawigacji po stronie klienta — Google ostrzega, że adresy oparte na fragmentach (#hash) to coś, czego “can’t reliably resolve.” (tłumaczenie) „nie potrafi niezawodnie rozwiązać”. Co najważniejsze, View Transitions to usprawnienie po stronie przeglądarki. Gdy Googlebot crawluje, wysyła żądanie do każdego adresu URL i otrzymuje zwykłą, kompletną stronę HTML — bazowa MPA pozostaje nietknięta. Przejścia wpływają tylko na to, co człowiek widzi w przeglądarce.

Nie, View Transitions nie zmieniają witryny Astro w SPA i nie psują SEO. Warto zauważyć, że dokumenty Astro dotyczące View Transitions nie mają sekcji SEO, co prawdopodobnie tłumaczy utrzymywanie się mitu „to psuje SEO”. Aby sprawdzić własną witrynę, pobierz bezpośrednio kilka adresów URL i potwierdź, że każdy zwraca pełny HTML — nie przyjmuj tego na wiarę, sprawdź własne wdrożenie.

Typowe błędy SEO w Astro

  1. Zakładanie, że Astro zajmie się SEO za Ciebie. Zajmuje się HTML-em. Meta, kanoniczne adresy, mapa witryny i schema są po Twojej stronie.
  2. Zapomnienie o site: w konfiguracji — mapa witryny po cichu się nie wygeneruje.
  3. Brak mapy witryny w robots.txt — Astro tego nie zrobi.
  4. Lazy loading obrazu LCP — nadpisz to dla hero przez eager + fetchpriority.
  5. Umieszczanie indeksowalnej treści w Server Island — crawlery widzą treść zastępczą, a Server Islands i tak wymagają adaptera.
  6. Pogoń za idealnym wynikiem Lighthouse i zatrzymanie się na tym. Szybkość jest sygnałem rankingowym, ale nie jedynym sygnałem rankingowym. Szybka pusta strona nie zajmuje pozycji — najwięcej pracy wykonują nadal treść, linki i E-E-A-T.
  7. Umieszczenie indeksowalnej treści wyłącznie w komponencie client:only. W przeciwieństwie do pozostałych dyrektyw client:*, client:only całkowicie pomija renderowanie serwerowe — dla tego komponentu nie ma HTML-u, dopóki przeglądarka go nie zahydratuje.
  8. Traktowanie „Astro jest statyczne/szybkie” jako gwarancji rezultatu. Statyczny lub generowany na żądanie HTML, wyspy i adaptery to mechanizmy — same z siebie nie gwarantują indeksowalności, indeksowania, rankingów ani Core Web Vitals. Zweryfikuj wdrożoną trasę, a nie diagram architektury.

Gdzie to pasuje w klastrze

Astro jest jednym, wyjątkowo przyjaznym SEO rozwiązaniem dla problemów z renderowaniem, które stawia JavaScript SEO, oraz popularnym frontendem dla wdrożeń bezgłowego CMS-a. Warstwa wydajności łączy się bezpośrednio z Core Web Vitals w klastrze wydajności stron, a dyscyplina sprawdzania „czy moja treść rzeczywiście znajduje się w HTML-u?” jest taka sama jak w klastrach crawlowania i indeksowania.

Add an expert note

Pin an expert quote

New person? Create their unclaimed profile at /admin/experts/ → Pin a quote first.