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

Opublikowano
24 kwietnia 2026
Aktualizacja
30 czerwca 2026
Czas czytania
8 min czytania

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.

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.

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.

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.

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.

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.

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.

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.

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