StriveLab
Strony internetowe
Usługi
RealizacjeO mnieBlogPorozmawiajmy
PL
EN

Astro

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

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.

SEO & Performance

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

Automatyzacja AI

Bezpieczne automatyzacje procesów i agenci AI w n8n, Make i Claude.

QA & Automation

Testy automatyczne komponentów i E2E w Cypress.

Konsultacje

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

StriveLab
Strony internetowe
Usługi
RealizacjeO mnieBlogPorozmawiajmy
PL
EN

Astro

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

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.

SEO & Performance

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

Automatyzacja AI

Bezpieczne automatyzacje procesów i agenci AI w n8n, Make i Claude.

QA & Automation

Testy automatyczne komponentów i E2E w Cypress.

Konsultacje

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

Astro

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

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.

SEO & Performance

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

Automatyzacja AI

Bezpieczne automatyzacje procesów i agenci AI w n8n, Make i Claude.

QA & Automation

Testy automatyczne komponentów i E2E w Cypress.

Konsultacje

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

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
  • Audyt SEO i Performance
  • Testy automatyczne i QA
  • Konsultacje Produktowe
  • Automatyzacja Procesów AI
  • Aplikacje webowe Next.js
  • Współpraca ciągła
Strony
  • O mnie
  • Usługi
  • Realizacje
  • Blog

© 2026 StriveLab.pl

Polityka prywatności
AstroArchitektura

Astro Content Collections — typowany blog z walidacją Zod od podstaw

Błędny frontmatter w Astro wykryty dopiero na produkcji? Content Collections z Zod sprawdzają schematy już w edytorze. Jak to skonfigurować?

OpublikujLinkedInFacebookWyślij
Autor
Maciej Sala
Opublikowano
24 kwietnia 2026 00:00
Czytanie
7 min czytania
Aktualizacja
9 czerwca 2026 10:00

Brak walidacji to prosta droga do błędów: literówki, brakujące opisy czy niespójne tagi stają się uciążliwym problemem, który odkryjemy dopiero na produkcji. eliminują to ryzyko, wymuszając zgodność każdego pliku ze zdefiniowanym schematem, co zatrzymuje build, zanim błędne dane trafią na serwer.

w skrócie

  • dają typowany model treści, walidację frontmatteru i bezpieczne query do wpisów.
  • W konfiguracja kolekcji opiera się na src/content.config.ts, loaderach i astro/zod.
  • Build-time collections są najlepsze dla blogów i dokumentacji, a dla danych zmiennych.
  • Największa wartość pojawia się, gdy schemat treści traktujesz jak kontrakt redakcyjny.

W tym artykule buduję system treści w Astro od pustej kolekcji do setupu, który nadaje się już do normalnej pracy. Będzie tutaj Zod, referencje między kolekcjami, typowane zapytania i błędy wyłapywane przed deployem.

Czym są Content Collections

Content Collection to uporządkowana grupa treści: wpisy blogowe, dokumentacja, strony produktowe, profile autorów. Astro ładuje je z plików albo zewnętrznych źródeł, przepuszcza przez schemat Zod i dopiero wtedy oddaje do szablonów. Błędny frontmatter nie przecieka na produkcję. Build pada wcześniej, z komunikatem, który da się szybko i łatwo poprawić.

W Astro 6 Content Collections są podzielone na dwa tryby: build-time (klasyczny, domyślny — dla blogów, dokumentacji) i live (runtime, dla danych zmieniających się w czasie rzeczywistym). W tym artykule skupimy się głównie na build-time, a Live Content Collections omówię w osobnej sekcji.

Cały mechanizm sprowadza się do jednego przepływu: źródło danych przechodzi przez loader, potem przez schemat Zod, a dopiero zwalidowane wpisy trafiają do typowanego store, z którego korzystają szablony. Jeśli walidacja nie przejdzie, build się zatrzymuje — błędne metadane nie mają jak dotrzeć do produkcji.

Diagram
Przepływ danych w Content Collections: walidacja Zod działa jak bramka przed buildem.

Konfiguracja kolekcji

Wszystkie kolekcje definiujesz w jednym pliku: src/content.config.ts. Poniżej minimalny przykład dla bloga:

Code
// src/content.config.ts
import { defineCollection } from 'astro:content'
import { glob } from 'astro/loaders'
import { z } from 'astro/zod'
 
const blog = defineCollection({
  loader: glob({
    pattern: '**/*.mdx',
    base: './src/content/blog',
  }),
  schema: z.object({
    title: z.string().max(80),
    description: z.string().min(50).max(160),
    date: z.coerce.date(),
    author: z.string().default('Maciej Sala'),
    tags: z.array(z.string()),
    image: z.string().optional(),
    draft: z.boolean().default(false),
    seo_aeo_geo: z.boolean().default(false),
  }),
})
 
export const collections = { blog }

Co tu się dzieje:

  • glob — , który przechodzi po plikach .mdx w src/content/blog i traktuje każdy jako osobny entry w kolekcji.
  • schema: z.object({...}) — definicja pól, jakie musi mieć frontmatter każdego pliku. Zod waliduje typy i wartości.
  • z.coerce.date() — Zod weźmie "2026-04-24" jako string i skonwertuje do obiektu Date. W szablonie masz gotowy obiekt do formatowania.
  • z.string().default('Maciej Sala') — jeśli autor nie jest podany, wtedy Astro użyje default.
  • draft: z.boolean().default(false) — pole do filtrowania szkiców.

Plik MDX bez title albo z description krótszym niż 50 znaków? Build zatrzymuje się z czytelnym komunikatem. W CI taki artykuł nie trafia na produkcję.

Struktura plików

Dla powyższej konfiguracji struktura wygląda tak:

Code
src/
├── content/
│   └── blog/
│       ├── astro-6-przewodnik.mdx
│       ├── islands-architecture.mdx
│       └── content-collections-tutorial.mdx
├── content.config.ts
└── pages/
    └── blog/
        ├── index.astro         ← lista artykułów
        └── [...id].astro       ← pojedynczy artykuł

Każdy plik MDX zaczyna się od frontmatteru YAML:

Code
---
title: 'Mój pierwszy wpis'
description: 'Krótki opis dla SEO i OG tags.'
date: 2026-04-24
tags: ['astro', 'poradnik']
---
 
# Treść wpisu
 
Tutaj normalna treść Markdown/MDX.

Generowanie stron z kolekcji

Kolekcja sama w sobie nie tworzy żadnych URL-i, ponieważ są to tylko typowane dane. Strony powstają w getStaticPaths, gdzie z każdego wpisu robisz osobną trasę. Astro buduje je statycznie w czasie builda, więc czytelnik dostaje gotowy HTML bez ani jednego zapytania w runtime:

Code
---
// src/pages/blog/[...id].astro
import { getCollection, render } from 'astro:content';
import Layout from '../../layouts/Layout.astro';
 
export async function getStaticPaths() {
  const posts = await getCollection('blog', ({ data }) => !data.draft);
  return posts.map((post) => ({
    params: { id: post.id },
    props: { post },
  }));
}
 
const { post } = Astro.props;
const { Content } = await render(post);
---
 
<Layout title={post.data.title} description={post.data.description}>
  <article>
    <header>
      <h1>{post.data.title}</h1>
      <time datetime={post.data.date.toISOString()}>
        {post.data.date.toLocaleDateString('pl-PL', {
          year: 'numeric',
          month: 'long',
          day: 'numeric',
        })}
      </time>
    </header>
 
    <Content />
  </article>
</Layout>

Kilka rzeczy wartych uwagi:

  • getCollection('blog', filterFn) — zwraca tablicę wszystkich entries z kolekcji, z opcjonalnym filtrem. Tutaj filtrujemy szkice.
  • post.id — Astro automatycznie generuje z nazwy pliku. astro-6-przewodnik.mdx → slug astro-6-przewodnik.
  • await render(post) — kompiluje MDX do komponentu Astro z nazwą Content, który renderuje treść.
  • Wszystkie pola (post.data.title, post.data.date) są typowane — TypeScript wie, co Zod zwalidował.

Lista artykułów

Strona z listą to ten sam getCollection, tylko zamiast budować trasy, po prostu sortujesz wpisy i renderujesz je w pętli. Filtr szkiców działa identycznie, a post.data jest cały czas typowane. IDE podpowie Ci każde pole:

Code
---
// src/pages/blog/index.astro
import { getCollection } from 'astro:content';
import Layout from '../../layouts/Layout.astro';
 
const posts = await getCollection('blog', ({ data }) => !data.draft);
const sorted = posts.sort(
  (a, b) => b.data.date.getTime() - a.data.date.getTime()
);
---
 
<Layout title="Blog — StriveLab">
  <h1>Blog</h1>
  <ul>
    {sorted.map((post) => (
      <li>
        <article>
          <a href={`/blog/${post.id}/`}>
            <h2>{post.data.title}</h2>
            <p>{post.data.description}</p>
            <time>{post.data.date.toLocaleDateString('pl-PL')}</time>
            <ul class="tags">
              {post.data.tags.map((tag) => <li>{tag}</li>)}
            </ul>
          </a>
        </article>
      </li>
    ))}
  </ul>
</Layout>

Rozwiązanie jest proste i w pełni typowane, a przy tym nie wymaga zewnętrznych bibliotek do parsowania Markdown ani ręcznego budowania pipeline'u. Wszystko, czego potrzeba, jest już wbudowane w Astro.

Referencje między kolekcjami

Chcesz, żeby artykuły miały autora, a autorzy byli osobną kolekcją? Zod + Astro mają na to wbudowany mechanizm, zwany reference().

Code
// src/content.config.ts
import { defineCollection, reference } from 'astro:content'
import { glob, file } from 'astro/loaders'
import { z } from 'astro/zod'
 
const authors = defineCollection({
  loader: file('src/content/authors.json'),
  schema: z.object({
    id: z.string(),
    name: z.string(),
    bio: z.string(),
    avatar: z.string(),
    linkedin: z.string().url().optional(),
  }),
})
 
const blog = defineCollection({
  loader: glob({ pattern: '**/*.mdx', base: './src/content/blog' }),
  schema: z.object({
    title: z.string(),
    description: z.string(),
    date: z.coerce.date(),
    author: reference('authors'), // ← referencja
    relatedPosts: z.array(reference('blog')).optional(),
    tags: z.array(z.string()),
  }),
})
 
export const collections = { authors, blog }

I src/content/authors.json:

Code
[
  {
    "id": "maciej-sala",
    "name": "Maciej Sala",
    "bio": "Founder StriveLab, frontend dev specjalizujący się w Astro i Next.js.",
    "avatar": "/images/authors/maciej.jpg",
    "linkedin": "https://linkedin.com/in/maciej-sala"
  }
]

Teraz w artykule w frontmatterze wpisujesz tylko ID autora:

Code
---
title: 'Mój wpis'
author: 'maciej-sala'
---

A w szablonie:

Code
---
import { getCollection, getEntry, render } from 'astro:content';
 
const post = // ... pobierasz post
const author = await getEntry(post.data.author);
---
 
<article>
  <h1>{post.data.title}</h1>
 
  <div class="author">
    <img src={author.data.avatar} alt={author.data.name} />
    <div>
      <p>{author.data.name}</p>
      <p>{author.data.bio}</p>
    </div>
  </div>
</article>

Referencje działają również dla tablic — możesz zdefiniować relatedPosts: z.array(reference('blog')) i trzymać listę powiązanych artykułów. Zod waliduje, że ID naprawdę istnieją w kolekcji, a literówkę w referencji wyłapuje się w build time.

Zaawansowana walidacja Zod

Zod daje Ci dużo więcej niż z.string(), a oto wzorce, których używam:

Code
const blog = defineCollection({
  loader: glob({ pattern: '**/*.mdx', base: './src/content/blog' }),
  schema: z.object({
    // Długość tytułu idealna dla SEO
    title: z.string().min(30).max(80),
 
    // Meta description w granicach, które Google wyświetla
    description: z.string().min(50).max(160),
 
    // Data w przeszłości
    date: z.coerce
      .date()
      .refine(
        (d) => d <= new Date(),
        'Data publikacji nie może być w przyszłości',
      ),
 
    // Enum tagów — błąd w build, jeśli ktoś wpisze nieistniejący tag
    tags: z
      .array(
        z.enum(['astro', 'next-js', 'react', 'seo', 'poradnik', 'javascript']),
      )
      .min(1)
      .max(5),
 
    // URL obrazu musi być lokalny lub HTTPS
    image: z
      .string()
      .refine(
        (url) => url.startsWith('/') || url.startsWith('https://'),
        'Obraz musi być lokalny lub HTTPS',
      )
      .optional(),
 
    // Czas czytania w minutach
    readingTime: z.number().int().positive().optional(),
 
    // Opcjonalny tytuł na social media (może być inny niż główny)
    ogTitle: z.string().max(60).optional(),
  }),
})

Każde pole wyłapuje inną klasę błędów: Enum tagów jest istotny przy większej liczbie artykułów, a bez niego mogą pojawiać się duplikaty w stylu „Next.js", „NextJS", „nextjs", które rozjeżdżają filtry i kategorie tagów.

Live Content Collections w Astro 6

Astro 6 wprowadza stabilne Live Content Collections dla danych, które zawsze muszą być świeże. Konfiguracja jest w osobnym pliku src/live.config.ts:

Code
// src/live.config.ts
import { defineLiveCollection } from 'astro:content'
import { z } from 'astro/zod'
 
const products = defineLiveCollection({
  loader: {
    name: 'products-api-loader',
    loadCollection: async () => {
      const response = await fetch('https://api.mystore.com/products')
      const products = await response.json()
      // Każdy entry musi mieć kształt { id, data }
      return {
        entries: products.map((product) => ({
          id: String(product.id),
          data: product,
        })),
      }
    },
    loadEntry: async ({ filter }) => {
      const response = await fetch(
        `https://api.mystore.com/products/${filter.id}`,
      )
      const product = await response.json()
      return { id: String(product.id), data: product }
    },
  },
  schema: z.object({
    id: z.string(),
    name: z.string(),
    price: z.number(),
    inventory: z.number(),
    updatedAt: z.coerce.date(),
  }),
})
 
export const liveCollections = { products }

W komponentach używasz tego przez getLiveCollection i getLiveEntry:

Code
---
import { getLiveCollection } from 'astro:content';
 
const { entries, error } = await getLiveCollection('products');
 
if (error) {
  console.error('Nie udało się pobrać produktów:', error);
}
---
 
{entries?.map((product) => (
  <div>
    <h3>{product.data.name}</h3>
    <p>{product.data.price} zł</p>
    <p>W magazynie: {product.data.inventory}</p>
  </div>
))}

W odróżnieniu od build-time collections, dane pobierane są w runtime i dlatego strona musi renderować się on-demand (output: 'server' albo trasa z prerender = false). W innym wypadku zapytanie wykona się raz, podczas builda. Używaj tego do rzeczy, które realnie muszą być aktualne (stan magazynu, ceny, oferta w czasie rzeczywistym).

Integracja z istniejącym CMS

Community zbudowało loadery dla popularnych : Sanity, Contentful, Storyblok, Strapi, Notion. Instalujesz pakiet, podajesz klucze , dostajesz typowaną kolekcję.

Code
// src/content.config.ts — z loaderem Storyblok
import { defineCollection } from 'astro:content'
import { storyblokLoader } from '@storyblok/astro'
import { z } from 'astro/zod'
 
const articles = defineCollection({
  loader: storyblokLoader({
    accessToken: process.env.STORYBLOK_TOKEN,
    contentTypes: ['article'],
    version: 'published',
  }),
  schema: z.object({
    title: z.string(),
    body: z.string(),
    seo: z.object({
      title: z.string(),
      description: z.string(),
    }),
  }),
})

W praktyce dla małych i średnich blogów rekomenduję pozostanie przy MDX w repo. Oznacza to wersjonowanie w Git, brak zewnętrznych zależności i pełną kontrolę. Z kolei dla zespołów z edytorami/copywriterami, którzy nie mają dostępu do repo, można użyć CMS.

SEO i structured data z Content Collections

Content Collections świetnie integrują się z generowaniem . W layoucie dla artykułu:

Code
---
// src/layouts/BlogPost.astro
const { post, author } = Astro.props;
 
const jsonLd = {
  '@context': 'https://schema.org',
  '@type': 'BlogPosting',
  headline: post.data.title,
  description: post.data.description,
  datePublished: post.data.date.toISOString(),
  author: {
    '@type': 'Person',
    name: author.data.name,
    url: author.data.linkedin,
  },
  image: post.data.image ? `https://strivelab.pl${post.data.image}` : undefined,
};
---
 
<script
  type="application/ld+json"
  set:html={JSON.stringify(jsonLd)}
/>

Ponieważ wszystko jest typowane, TypeScript łapie wszelakie literówki i brakujące pola zanim strona pojawi się na produkcji. To element, który opisuję szerzej w artykule o SEO w Astro.

Pułapki, na które warto uważać

Kilka błędów wraca w niemal każdym projekcie. Większość kosztuje godzinę debugowania, choć każdy z nich da się uprzedzić jednym zdaniem.

Mieszanie id i slug w routingu. Plik trasy [...id].astro musi mieć params: { id: post.id }. Jeśli nazwiesz parametr slug, a w pliku użyjesz [...id] (albo odwrotnie), Astro nie znajdzie dopasowania i strony po prostu się nie wygenerują. Trzymaj jedną konwencję w całym projekcie — id jest tą zalecaną przez dokumentację.

Brak prerender = false przy Live Collections. Live Collections pobierają dane w runtime, więc strona, która z nich korzysta, musi renderować się na żądanie. Bez output: 'server' albo export const prerender = false zapytanie wykona się raz, podczas builda, i „świeże" dane zamrożą się na moment deployu, czyli dokładnie to, czego chciałeś uniknąć.

z.coerce.date() a strefy czasowe. Zapis date: 2026-04-24 w YAML parsuje się jako północ UTC. Jeśli formatujesz datę lokalnie w strefie ujemnej względem UTC, wpis potrafi „cofnąć się" o jeden dzień. Przy datach publikacji nie jest to jakiś problem, ale przy harmonogramach czy embargach warto zapisywać pełny timestamp ze strefą.

Zbyt restrykcyjny enum tagów na starcie. Enum świetnie eliminuje duplikaty, ale jeśli zamkniesz listę zbyt wcześnie, każdy nowy temat wymaga zmiany w content.config.ts i ponownego builda. Na małym blogu to akceptowalne, ale przy większym zespole rozważ osobną kolekcję tagów z reference(), żeby dodanie tagu nie było zmianą w kodzie.

Wskazówka

Dobra schema Content Collections eliminuje więcej błędów redakcyjnych niż checklisty w Notion. Niepoprawny wpis po prostu nie przejdzie buildu i nigdy nie trafi na produkcję.

Kontrakt redakcyjny

Prawdziwa moc Content Collections ujawnia się, gdy ich schemat staje się umową z autorem treści.

  • title i description ustaw jako wymagane, ponieważ bez nich i podglądy w social mediach zaczynają się sypać.

  • date waliduj przez z.coerce.date(), żeby zwykły tekst nie przeszedł jako data.

  • tags trzymaj w ograniczonej liście, bo inaczej szybko dostaniesz trzy wersje tego samego tagu: „Next.js", „NextJS" i „nextjs".

  • canonical oraz redirectFrom dopisz do schematu, jeśli zmieniasz slugi albo migrujesz treści.

  • pola robocze typu featured czy draft też trzymaj w schemacie, ponieważ wtedy wyróżnianie wpisów i ukrywanie szkiców jest typowane, co przekłada się na większy porządek.

Werdykt Labu

to jeden z tych mechanizmów, które mogą być początkowo niedoceniane, a potem okazuje się, że bardzo pomagają w utrzymaniu projektu na odpowiednim poziomie. Przy 20 artykułach widzisz pierwsze oszczędności, a przy 100+ przestajesz wyobrażać sobie pracę bez walidacji, ponieważ każda literówka w metadanych kończy się błędem buildu. Produkcja jest wtedy dużo bardziej bezpieczna i mniej podatna na wycieki drobnych błędów.

Stąd jedna zasada: wdrażaj Content Collections od pierwszego artykułu, nie od trzydziestego, ponieważ refactor istniejącej treści bez jest znacznie droższy niż zaprojektowanie go na starcie.

Ultraszybkie projekty, łączące lekkość ze skalowalnością.
Astro
  • Czym są Content Collections1 min
  • Konfiguracja kolekcji1 min
  • Struktura plików1 min
  • Generowanie stron z kolekcji1 min
  • Lista artykułów1 min
  • Referencje między kolekcjami1 min
  • Zaawansowana walidacja Zod1 min
  • Live Content Collections w Astro 61 min
  • Integracja z istniejącym CMS1 min
  • SEO i structured data z Content Collections1 min
  • Pułapki, na które warto uważać2 min
  • Kontrakt redakcyjny1 min
  • Werdykt Labu1 min

Często zadawane pytania

Źródła i dokumentacjaZweryfikowano: 9 czerwca 2026

Materiały wykorzystane do weryfikacji artykułu o Content Collections w Astro:

Astro docs: Content Collections, Astro docs: Content Loaders, Zod documentation, Astro docs: Live Content Collections.

Seria

Astro w praktyce 2026
Część 5 / 10
  1. 1Pierwszy projekt w Astro — od npm create astro do wdrożenia w 15 minut
  2. 2Astro 6 — przewodnik po nowościach: Cloudflare Workers, Live Content Collections, Fonts API i CSP
  3. 3Architektura wysp w Astro — czym są wyspy i dlaczego zero JS domyślnie zmienia zasady gry
  4. 4Client directives w Astro — client:load, client:idle, client:visible, client:media, client:only w praktyce
  5. Astro Content Collections — typowany blog z walidacją Zod od podstaw
  6. 6Server Islands w Astro — dynamiczne fragmenty na statycznej stronie
  7. 7Astro View Transitions — płynne przejścia między stronami bez budowania SPA
  8. 8SEO w Astro — Core Web Vitals, dane uporządkowane i techniczny fundament rankingu w 2026
  9. 9Migracja bloga z WordPress na Astro — eksport treści, przekierowania 301 i zachowanie pozycji w Google
  10. 10Lighthouse 100/100 w Astro — case study optymalizacji strony usługowej
Maciej Sala

O autorze

Maciej Sala

Maciej Sala — Product Manager i Frontend Developer z bogatym doświadczeniem w marketingu internetowym oraz SEO. Na co dzień pracuje z Reactem, Next.js i TypeScriptem, a ostatnio także z Astro i narzędziami do automatyzacji procesów AI. Sprawnie łączy perspektywę produktową z praktycznym podejściem do kodu. Przez kilka lat był związany z branżą gier wideo jako project manager i game designer. Absolwent historii na Uniwersytecie Jagiellońskim oraz studiów podyplomowych z marketingu internetowego na AGH w Krakowie. Po godzinach trenuje na siłowni, maluje figurki i rozwija własne projekty side-projecty.

Moje artykułyWięcej o mnie

Pomagam przekładać takie tematy na konkretne wdrożenia w frontendzie, SEO, analityce i procesie produktowym.

Skontaktuj się ze mną

Biblioteka wiedzy

Czytaj dalej

Zobacz więcej wpisów
Astro 6 — przewodnik po nowościach: Cloudflare Workers, Live Content Collections, Fonts API i CSP
Astro 6 — przewodnik po nowościach: Cloudflare Workers, Live Content Collections, Fonts API i CSP

Astro 6 z Cloudflare Workers w dev, Live Collections i wbudowanym Fonts API. Co te zmiany oznaczają dla Twoich projektów na produkcji?

Maciej Sala

Maciej Sala

Founder Strivelab

24 kwietnia 2026
Astro.js vs Next.js w 2026 — kompleksowe porównanie frameworków
Astro.js vs Next.js w 2026 — kompleksowe porównanie frameworków

Astro 6 vs Next.js 16 — zupełnie różne założenia. Które wybrać do strony usługowej, bloga, SaaS i e-commerce? Decydujące kryteria.

Maciej Sala

Maciej Sala

Founder Strivelab

15 kwietnia 2026
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

Astro ma przewagę SEO z założenia — ale tylko jeśli wiesz, jak ją wykorzystać. Core Web Vitals, JSON-LD i GEO/AEO w jednym miejscu.

Maciej Sala

Maciej Sala

Founder Strivelab

24 kwietnia 2026

Poprzedni wpis

Server Islands w Astro — dynamiczne fragmenty na statycznej stronie
Server Islands w Astro — dynamiczne fragmenty na statycznej stronie

Statyczna strona z dynamicznymi fragmentami — Server Islands w Astro łączą szybkość CDN z personalizacją SSR. Jak to działa w praktyce?

Maciej Sala

Maciej Sala

Founder Strivelab

24 kwietnia 2026

Następny wpis

Client directives w Astro — client:load, client:idle, client:visible, client:media, client:only w praktyce
Client directives w Astro — client:load, client:idle, client:visible, client:media, client:only w praktyce

client:load, client:idle czy client:visible? Zła dyrektywa niszczy wydajność Astro. Kiedy używać której — z benchmarkami i typowymi błędami.

Maciej Sala

Maciej Sala

Founder Strivelab

24 kwietnia 2026