Przejdź do treści

Astro i Cloudflare Workers — wdrożenie, bindings i lokalne środowisko programistyczne

Astro na Cloudflare Workers — adapter, bindings KV/R2/D1 i lokalne środowisko z workerd. Limity, które trzeba znać przed wdrożeniem na brzegu sieci.

Maciej Sala

Founder StriveLab

9 min czytaniaOpublikowano 24 kwietnia 2026 (Aktualizacja 30 czerwca 2026)

w Astro dostał bardzo mocną integrację: lokalnie, do KV/R2/D1 bez ręcznych atrap i działający w środowisku na brzegu sieci. To nie jest demo z dokumentacji. To konfiguracja, na której można oprzeć zwykłą stronę produkcyjną.

Dlaczego wybrać Cloudflare Workers dla Astro zamiast Cloudflare Pages

Aktualny adapter Cloudflare dla Astro celuje w Workers. Cloudflare rekomenduje Workers dla nowych projektów, a sam adapter nie wspiera już wdrożeń na Cloudflare Pages. Aktualnie Pages dalej mają zastosowanie prostych statycznych stron, ale weź pod uwagę Workers, jeśli wchodzą SSR, Server Islands, Actions, Sessions albo bindings.

Istniejący projekt na Pages? Migracja jest przewidywalna, z racji tego, że Cloudflare przygotował oficjalny przewodnik migracyjny, a większość konfiguracji przenosi się 1:1.

Jak zainstalować adapter Cloudflare w Astro

Standardowa ścieżka:

Code
npx astro add cloudflare

To instaluje aktualny @astrojs/cloudflare, dodaje do astro.config.mjs odpowiednią konfigurację i pozwala później dopisać wrangler.jsonc, w sytuacji, kiedy potrzebujesz bindings, środowisk albo niestandardowych ustawień Workera.

Po instalacji Twój astro.config.mjs wygląda mniej więcej tak:

Code
import { defineConfig } from 'astro/config'
import cloudflare from '@astrojs/cloudflare'
 
export default defineConfig({
  output: 'server',
  adapter: cloudflare({
    imageService: 'cloudflare-binding',
  }),
})

Są dwie rzeczy, na które warto zwrócić uwagę:

  • output: 'server' — cały projekt Astro renderuje się na żądanie, na brzegu sieci. Alternatywnie klasyczne 'static' (w tym wypadku adapter nie jest potrzebny). Tryb 'hybrid' nie istnieje od Astro 5.0 — został scalony ze 'static': domyślnie strony są prerenderowane, a pojedyncze trasy oznaczasz export const prerender = false, by renderować je na żądanie.
  • imageService: 'cloudflare-binding' — domyślna w aktualnym adapterze transformacja obrazów przez Cloudflare Images binding. Alternatywnie 'compile' dla optymalizacji w czasie budowania na trasach prerenderowanych albo 'passthrough', jeśli masz własny proces obsługi obrazów.

Lokalne środowisko Astro na Cloudflare Workers: workerd zamiast Node

To największa zmiana dla użytkowników Cloudflare po przejściu na nowy adapter. Wcześniej astro dev działał w Node.js, a produkcja w workerd. Teraz lokalne środowisko działa w tym samym workerd co produkcja — klasyczny błąd „działa lokalnie, nie działa na produkcji" jest dużo łatwiejszy do złapania przed wdrożeniem.

Code
npm run dev

Pod spodem Astro:

  1. Bootstrapuje Vite z Cloudflare Vite plugin.
  2. Uruchamia workerd jako środowisko wykonawcze dla Twojego kodu.
  3. Zapewnia dostęp do API platformy (KV, R2, D1, Durable Objects) — lokalnie, bez ręcznych atrap.

Skutek jest prosty: kod z cloudflare:workers API działa tak samo w dev i na produkcji. Stary dostęp przez Astro.locals.runtime znika, obejścia przestają być potrzebne, a importy z cloudflare:* działają bezpośrednio w astro dev.

Bindings w Astro na Cloudflare Workers: KV, R2, D1 i Durable Objects

Bindings to sposób, w jaki Worker (i Twoje Astro) łączy się z zasobami Cloudflare: (magazyn klucz-wartość), (przechowywanie plików zgodne z S3), (SQLite), (obliczenia z własnym stanem).

Konfigurujesz je w wrangler.jsonc:

Code
{
  "name": "moja-astro-strona",
  "main": "@astrojs/cloudflare/entrypoints/server",
  "compatibility_date": "2026-06-30",
  "compatibility_flags": ["nodejs_compat"],
  "assets": {
    "directory": "./dist",
  },
  "kv_namespaces": [
    {
      "binding": "SESSIONS",
      "id": "xxx",
    },
  ],
  "r2_buckets": [
    {
      "binding": "MEDIA",
      "bucket_name": "strivelab-media",
    },
  ],
  "d1_databases": [
    {
      "binding": "DB",
      "database_name": "strivelab-production",
      "database_id": "yyy",
    },
  ],
}

A w kodzie Astro korzystasz z nich przez bezpośredni import z cloudflare:workers:

Code
// src/pages/api/get-session.ts
import type { APIRoute } from 'astro'
import { env } from 'cloudflare:workers'
 
export const prerender = false
 
export const GET: APIRoute = async ({ request }) => {
  const sessionId = request.headers.get('X-Session-Id')
  const session = await env.SESSIONS.get(sessionId, 'json')
 
  if (!session) {
    return new Response(null, { status: 404 })
  }
 
  return new Response(JSON.stringify(session), {
    headers: { 'Content-Type': 'application/json' },
  })
}

TypeScript wie o Twoich bindings, więc po uruchomieniu wrangler types w worker-configuration.d.ts pojawiają się typy, które obejmują import env z cloudflare:workers.

Jak typować bindings Cloudflare w projekcie Astro

Nie dopisuj już ręcznie typu Runtime do App.Locals, jeśli używasz aktualnego adaptera. Po zmianie wrangler.jsonc, .dev.vars albo listy bindings uruchamiasz:

Code
npx wrangler types

Warto podpiąć to pod skrypty projektu:

Code
{
  "scripts": {
    "cf:types": "wrangler types",
    "dev": "wrangler types && astro dev",
    "build": "wrangler types && astro build"
  }
}

Teraz env.DB.prepare(...), env.SESSIONS.get(...) albo env.MEDIA.put(...) mają podpowiadanie typów, a TypeScript zgłasza błąd, jeśli próbujesz użyć bindingu, którego nie ma w konfiguracji.

Praca z lokalną bazą D1: migracje, dane i flaga --local

Sam binding to dopiero połowa sukcesu, ponieważ bazę D1 trzeba jeszcze wypełnić schematem i danymi, i tu czeka najczęstsza pułapka. Wrangler (od wersji 3+) domyślnie trzyma dane lokalnie, w odizolowanym storage, oddzielnie od produkcji. To celowe i bezpieczne: lokalna sesja nie ma dostępu do produkcyjnych danych, a dane utrwalają się między kolejnymi uruchomieniami dev servera.

Migracje i zapytania na lokalnej bazie uruchamiasz z flagą --local:

Code
# Schemat na LOKALNEJ bazie — nie dotyka produkcji
wrangler d1 execute strivelab-production --local \
  --command "CREATE TABLE IF NOT EXISTS users (
    user_id INTEGER PRIMARY KEY,
    email_address TEXT,
    created_at INTEGER
  );"

Jeśli lokalna baza „dziwnie" jest pusta po ponownym uruchomieniu, przyczyna prawie zawsze jest ta sama: migracje poszły na niewłaściwą instancję. Sprawdź, czy faktycznie zaaplikowałeś je z flagą --local, a nie na zdalnej bazie albo w innym katalogu projektu. To samo dotyczy seedowania danych testowych — jeden plik .sql z danymi startowymi puszczony przez wrangler d1 execute --local --file=./seed.sql daje powtarzalny stan lokalny, który każdy w zespole odtworzy jedną komendą.

Wdrożenie Astro na Cloudflare Workers przez Wrangler

Wdrożenie robisz przez Wrangler:

Code
npm run build
npx wrangler deploy

Albo połączenie w jednej komendzie w package.json:

Code
{
  "scripts": {
    "deploy": "astro build && wrangler deploy"
  }
}

Wrangler wysyła build (statyczne zasoby oraz Worker) na Cloudflare. Pierwsze wdrożenie tworzy Worker pod adresem {name}.{twoja-subdomena}.workers.dev, a potem dodajesz własną domenę w panelu Cloudflare.

W CI/CD najprostszy wariant to osobne zadanie GitHub Actions z oficjalną akcją Cloudflare:

Code
name: Wdrożenie Astro na Cloudflare Workers
 
on:
  push:
    branches: [main]
 
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: npm
      - run: npm ci
      - run: npm run build
      - uses: cloudflare/wrangler-action@v3
        with:
          apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
          accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
          command: deploy

Do środowiska testowego dodajesz osobną gałąź albo ręczne uruchamianie procesu CI/CD i zmieniasz komendę na deploy --env staging. Pamietaj, że jeśli prerender używa zmiennych środowiskowych, build dla środowiska testowego i produkcji powinien być wykonany osobno.

Środowiska w Astro i Cloudflare Workers: podgląd, testy i produkcja

Od Astro 6 sposób obsługi środowisk stał się znacznie bardziej rygorystyczny. W Astro 5 budowałeś raz i deployowałeś z flagą --env, a teraz build musi być oddzielny dla każdego środowiska, bo pre-rendering używa innych wartości zmiennych.

Code
# Produkcja
CLOUDFLARE_ENV=production astro build
wrangler deploy
 
# Środowisko testowe
CLOUDFLARE_ENV=staging astro build
wrangler deploy --env staging

W wrangler.jsonc:

Code
{
  "name": "moja-strona",
  "env": {
    "staging": {
      "name": "moja-strona-staging",
      "vars": {
        "API_URL": "https://api-staging.example.com",
      },
    },
    "production": {
      "name": "moja-strona",
      "vars": {
        "API_URL": "https://api.example.com",
      },
    },
  },
}

Dla większości projektów rekomenduję osobny proces CI/CD dla każdego środowiska. GitHub Actions z osobnym zadaniem dla środowiska testowego i produkcji, uruchamianym z innej gałęzi.

Remote bindings w Astro: zdalne zasoby w lokalnym środowisku

Domyślnie lokalne środowisko korzysta z lokalnych wersji zasobów. To bezpieczne, ponieważ testujesz kod bez ryzyka przypadkowego zapisu do produkcyjnej bazy D1 albo bucketu R2. Problemy zaczynają się wtedy, gdy lokalna baza nie ma prawdziych danych i cały scenariusz testowy robi się sztuczny, przez co mający słabsze odniesienie do rzeczywistości.

Do takich przypadków służą zdalne bindings (remote bindings). W konfiguracji oznaczasz konkretny binding jako zdalny:

Code
{
  "d1_databases": [
    {
      "binding": "DB",
      "database_name": "moja-baza-staging",
      "database_id": "staging-database-id",
      "remote": true,
    },
  ],
}

Mechanizm nie należy do skomplikowanych, ponieważ twój kod nadal uruchamia się lokalnie w workerd, ale zapytania do wskazanego zasobu są przekazywane do realnego zasobu na koncie Cloudflare. Jest do dobre rozwiązanie do testów integracyjnych na danych ze środowiska testowego, weryfikacji migracji i debugowania problemów, których lokalna symulacja nie odtwarza.

Warto też pamiętać o kosztach i opóźnieniach: lokalny kod jest szybki, ale każde odwołanie do zdalnego zasobu przechodzi przez sieć i może naliczać operacje tak jak normalne użycie usługi Cloudflare.

Astro na Cloudflare Workers: wynik statyczny czy serwerowy

Najczęstszy błąd przy wdrożeniach Astro na Cloudflare to dodanie adaptera bez decyzji, czy projekt naprawdę potrzebuje środowiska wykonawczego Workera.

TrybKiedy używaćKonsekwencja
output: 'static'Blog, dokumentacja, landing, portfolio bez dynamicznych endpointówBrak adaptera i brak bindings; wynik można serwować z dowolnego CDN
output: 'static' + prerender = falseWiększość stron statyczna, pojedyncze endpointy lub Server IslandsAdapter potrzebny tylko dla tras renderowanych na żądanie
output: 'server'Cały projekt zależy od cookies, sesji, D1/KV/R2 albo dynamicznych danychKażda trasa przechodzi przez środowisko wykonawcze Workera

Optymalizacja obrazów w Astro na Cloudflare

Aktualny adapter Cloudflare może używać Cloudflare Images binding do optymalizacji obrazów. Zamiast optymalizacji podczas budowania w Node (), obrazy są przekształcane na brzegu sieci w czasie żądania, jeśli używasz domyślnego imageService: 'cloudflare-binding'.

Code
---
import { Image } from 'astro:assets';
import heroImage from '../assets/hero.jpg';
---
 
<Image src={heroImage} alt="Hero" width={1200} height={630} format="webp" />

Efekt? Obraz automatycznie zmniejszany, kompresowany i serwowany przez najbliższy punkt Cloudflare. Żadnej pracy w czasie builda i żadnego konfigurowania .

Jeśli wolisz klasyczną optymalizację podczas budowania (np. masz już proces obróbki zdjęć w repozytorium), ustaw imageService: 'compile' w konfiguracji adaptera. Jeśli obrazy obsługuje zewnętrzny CDN albo CMS, możesz użyć imageService: 'passthrough'.

Debugowanie Cloudflare Workers na produkcji

Cloudflare Workers Dashboard daje Ci wgląd w logi, metryki i odsetek błędów. W codziennej pracy przydaje się też:

Code
# Tail logów produkcyjnych w terminalu
wrangler tail

To przesyła logi w czasie rzeczywistym ze wszystkich instancji Workera. Przydatne szczególnie do debugowania problemów, które nie pojawiają się lokalnie.

Dla bardziej zaawansowanego monitoringu rozważ Cloudflare Workers Analytics Engine (do custom metrics) albo integrację z Sentry przez @sentry/cloudflare.

Zmienne środowiskowe i sekrety w Cloudflare Workers

Dwie kategorie:

Vars — jawne zmienne dostępne w kodzie i zapisywane w wrangler.jsonc:

Code
{
  "vars": {
    "PUBLIC_SITE_URL": "https://example.com",
    "DEFAULT_LOCALE": "pl",
  },
}

Secrets — ustawiane przez Wrangler CLI, szyfrowane po stronie Cloudflare, nie trafiają do kodu:

Code
wrangler secret put DATABASE_URL
# wrangler zapyta o wartość interaktywnie

Dla lokalnego środowiska tworzysz .dev.vars:

Code
# .dev.vars (dodany do .gitignore)
DATABASE_URL=postgres://localhost:5432/dev
API_KEY=secret-key

W kodzie dostęp przez env.DATABASE_URL po imporcie z cloudflare:workers.

Limity Cloudflare Workers dla projektów Astro

Workers nie są Node.js i ta różnica ma znaczenie przed zaprojektowaniem architektury. Limit czasu CPU w planie darmowym wynosi 10 ms na żądanie, a w planie płatnym domyślnie 30 s, z możliwością podniesienia do 5 minut. Czas CPU to nie całkowity czas odpowiedzi, więc fetch() do zewnętrznego API nie liczy się w ten sam sposób, ale ciężkie obliczenia — przetwarzanie dużych JSON-ów, kryptografia, manipulacja obrazami — mogą trafić w ścianę.

Rozmiar paczki nie może przekroczyć 3 MB po kompresji w planie darmowym i 10 MB w planie płatnym. Dla typowego projektu Astro to nie problem, ale uważaj na moment.js, lodash bez i pełne AWS SDK. Workers nie mają fs: statyczne zasoby są serwowane przez Assets binding, a nie przez czytanie plików w środowisku wykonawczym. Limit dodatkowych zapytań z jednego wywołania Workera wynosi 50 w planie darmowym i 10 000 w planie płatnym. Dla stron z wieloma wywołaniami API weryfikuj ten limit przed wdrożeniem, nie po.

Cloudflare Workers czy Vercel: kiedy wybrać które wdrożenie

W 2026 roku to realny podział rynku. Dane z projektów wskazują jasno:

Cloudflare + Astro wygrywa przy globalnym ruchu, niskim budżecie i usługach przechowywania danych blisko kodu: KV, R2, D1. Vercel zostaje lepszym wyborem przy Next.js, React Server Components, PPR i zespole, który ma już dobrze ułożony proces pracy. Nie przenosiłbym takiego projektu na siłę.

Dla stron Astro — domyślny wybór to Cloudflare, a dla aplikacji Next.js, będzie to Vercel. Szersze porównanie frameworków opisałem w osobnym artykule.

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

Często zadawane pytania

Czy mogę używać Astro na Cloudflare bez Workers, tylko jako statyczny hosting?

Tak. Przy output: 'static' Astro generuje czysty SSG, który działa na dowolnym CDN, wliczając w to Cloudflare przez Workers Static Assets. Adapter Cloudflare jest potrzebny wyłącznie dla renderowania na żądanie (output: 'server' albo pojedyncze trasy z prerender = false). Statyczny wynik budowania nie wymaga żadnego adaptera.

Jakie są realne koszty Astro na Cloudflare Workers?

Plan darmowy obejmuje 100 000 żądań dziennie i 10 ms CPU na żądanie. Plan płatny Workers kosztuje $5 miesięcznie, obejmuje 10 mln żądań i 30 s CPU. Dla strony z 50k–100k odsłon miesięcznie koszt zwykle pozostaje zerowy, a dla większości projektów treściowych Cloudflare jest znacząco tańszy niż Vercel.

Czy Astro z adapterem Cloudflare działa na innym hoście?

Nie. Build z adapterem Cloudflare jest przygotowany pod środowisko wykonawcze workerd. Dla przenośności, output: 'static' działa wszędzie, a adapter Node.js działa na każdym hostingu Node.

Czym różni się Cloudflare Images binding od zwykłej optymalizacji obrazów Astro?

Optymalizacja przez sharp generuje warianty obrazów podczas budowania — wydłuża build i zwiększa rozmiar katalogu wynikowego. Cloudflare Images binding przekształca obrazy na żądanie, blisko użytkownika, bez pracy wykonywanej w czasie builda. Przy dużych galeriach produktowych zmienia to całą logistykę obrazów.

Czy mogę używać Prisma/Drizzle ORM z D1?

Prisma ma oficjalne wsparcie D1 przez @prisma/adapter-d1. Drizzle ma bezpośrednie wsparcie D1 i jest lżejszy — co ma znaczenie dla Workers, gdzie rozmiar paczki wpływa na czas zimnego startu. Dla projektów Astro + Cloudflare domyślnie wybieram Drizzle.

Jak dziś czytać bindings w Astro na Cloudflare Workers?

W aktualnym adapterze nie używaj już Astro.locals.runtime.env ani context.locals.runtime.env. Bindings, zmienne i sekrety importujesz bezpośrednio z cloudflare:workers, np. import { env } from 'cloudflare:workers'. Typy generujesz komendą wrangler types.

Czym różni się komenda D1 z flagą `--local` od tej bez niej?

Z --local komendy Wranglera działają na lokalnej, izolowanej bazie D1, która nie dotyka produkcji. Bez tej flagi wykonują się na zdalnej, produkcyjnej bazie w sieci Cloudflare. Brak --local traktuj jak ostrzeżenie „celujesz w produkcję" — to najczęstsza pułapka początkujących i źródło przypadkowych zmian na żywych danych.

Czy lokalna baza D1 zachowuje dane między uruchomieniami?

Tak. Od Wranglera w wersji 3+ dane lokalne są domyślnie utrwalane między kolejnymi uruchomieniami dev servera, w odizolowanym lokalnym storage. Jeśli lokalna baza nagle jest pusta, najczęstsza przyczyna to migracje zaaplikowane na niewłaściwej instancji — sprawdź, czy faktycznie poszły z flagą --local.

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 rozwijam własne projekty.

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

Skontaktuj się ze mną

Biblioteka wiedzy na temat Astro

Czytaj dalej

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

Rynek frameworków podzielił się wyraźnie: Vercel + Next.js kontra Cloudflare + Astro. Astro 6 wprowadza dużo wartościowych nowości, które wyraźnie zmieniają model pracy. W tym wpisie pokazuję, co realnie zmieniło się z perspektywy technicznej i co musisz sprawdzić przed migracją.

Maciej Sala

Maciej Sala

Founder StriveLab

Koszty utrzymania Astro i Cloudflare: kiedy statyczna strona jest tańsza niż WordPress

Faktura za hosting to czubek góry lodowej. Pod nią: aktualizacje wtyczek, konflikty wersji, incydenty bezpieczeństwa w niedzielę o 23:00, regresy po każdym update i czas programisty, który sprawdza, czy formularz nadal wysyła maile. TCO WordPressa jest zawsze wyższe niż wygląda na początku.

Maciej Sala

Maciej Sala

Founder StriveLab

Cloudflare i samodzielne hostowanie Next.js

Samodzielnie hostowany Next.js na VPS daje kontrolę nad kosztami i konfiguracją, ale też zrzuca na nas odpowiedzialność za DNS, TLS, cache, ochronę przed atakami i prawdziwe IP klienta w logach. Cloudflare może stanąć przed Twoim serwerem jako bezpłatna warstwa CDN, SSL i podstawowej ochrony DDoS, o ile nie zaczniesz mechanicznie cachować całej aplikacji.

Maciej Sala

Maciej Sala

Founder StriveLab