Migrare un sito Astro da Cloudflare Pages a Workers: cosa cambia davvero

Da Pages a Workers non sposti file: rendi esplicito quello che Pages faceva da solo. 404, binding ASSETS, ordine delle risposte, variabili di build. Per Astro la scadenza la fissa l'adapter: dalla v13, quella di Astro 6, Pages non è più supportato.

Francesco Pio Nocerino7 minAstro
Migrare un sito Astro da Cloudflare Pages a Workers: cosa cambia davvero
Indice

Questo pezzo è per chi ha un sito Astro su Cloudflare Pages e si chiede se spostarlo su Workers, e cosa si rompe nel farlo. Fa parte del filone Cloudflare di fnbit, accanto a Workers + D1 + R2 e al confronto Vercel vs Cloudflare vs VPS.

Non è il diario di una migrazione. Non ho cronometri né log da mostrarti. È una procedura costruita sulla documentazione ufficiale di Cloudflare e di Astro, verificata il 14 ottobre 2026, con le versioni lette quel giorno dal registry npm.

In breve: passare da Pages a Workers vuol dire rendere esplicito quello che Pages faceva da solo. Pagina 404, comportamento SPA, binding ASSETS, ordine tra Functions e file statici, variabili di build: su Workers li dichiari tu nel file Wrangler. Per chi usa Astro la scadenza la fissa l'adapter: da @astrojs/cloudflare v13, quella che serve per Astro 6, il deploy su Pages non è più supportato. Se resti su Astro 5 puoi aspettare. Se aggiorni, migri.

Pages e Workers, in due righe

Cloudflare Pages è il servizio nato per siti statici e Jamstack, con build da Git e Pages Functions per la parte server. Cloudflare Workers è la piattaforma di calcolo serverless di Cloudflare, che oggi serve anche file statici tramite Workers Static Assets. Le due cose si sono avvicinate, ma non coincidono.

La domanda sbagliata

Non "Workers è meglio di Pages?". È: cosa faceva Pages al posto mio, e dove lo devo scrivere adesso?

Pages indovinava. Guardava se c'erano index.html e 404.html e decideva da solo se il tuo era un sito statico o una SPA. Dava un binding ASSETS già pronto. Eseguiva le Functions prima dei file statici. Su Workers nessuna di queste cose è automatica: la guida ufficiale di migrazione lo dice chiaramente, per evitare configurazioni sbagliate per caso.

Il costo dichiarato non cambia molto. Le richieste agli asset statici restano gratuite e le invocazioni costano come prima, secondo Cloudflare. Quello che cambia è il lavoro di configurazione, e chi lo fa.

Quando ti tocca farlo

Il motivo concreto, per un sito Astro, è la versione dell'adapter.

La documentazione di @astrojs/cloudflare è netta. Astro 6 richiede l'adapter v13 o successivo, e la v13 ha rimosso il supporto a Cloudflare Pages. Al 14 ottobre 2026 l'ultima versione su npm è la 14.3.4, che chiede Astro 7.2 o superiore e Wrangler 4.125 o superiore.

Quindi la decisione non è "migro o no". È "quando aggiorno Astro". Il sito statico che gira su Pages con Astro 5 non smette di funzionare domani. Ma ogni aggiornamento di Astro che vuoi fare passa da qui.

Cosa cambia: tabella rapida

Cosa

Su Pages

Su Workers

Cartella di output

pages_build_output_dir

assets.directory

Pagina 404 e SPA

Dedotte dai file presenti

not_found_handling esplicito

Binding agli asset

ASSETS automatico

assets.binding da dichiarare

Chi risponde prima

Functions, poi asset

Asset, poi Worker (salvo run_worker_first)

_headers e _redirects

Supportati

Supportati, ma solo sugli asset statici

Variabili

Build e runtime condivise

Separate: le variabili di build vanno in Workers Builds

Comandi

wrangler pages dev / deploy

wrangler dev / deploy

Porta locale

8788

8787

Dominio

Anche fuori da Cloudflare, via CNAME

Solo con nameserver su Cloudflare

Preview

Automatiche per ogni branch

preview_urls e blocco previews da attivare

La riga che fa più danni è la quinta. Ci torno sotto.

Prima di toccare il codice

Tre controlli che decidono quale strada prendi.

  • Il sito è tutto statico? Se Astro prerende ogni pagina, non ti serve l'adapter. Ti basta un file Wrangler con la cartella degli asset.
  • C'è una cartella `functions/`? Se usi Pages Functions fuori da Astro, vanno compilate in un Worker con wrangler pages functions build.
  • Che versione di Astro hai? Con Astro 5 e adapter v12 il punto d'ingresso è un file generato. Con Astro 6 o superiore è un modulo dell'adapter. Le due guide ufficiali mostrano esempi diversi proprio per questo.

Aggiorna anche Wrangler: la guida di migrazione parte dalla v4. Se ti stai chiedendo se usare ancora Wrangler, ne ho parlato in cf al posto di Wrangler: per questi comandi Wrangler resta il riferimento della documentazione.

Caso 1: sito Astro statico

È il caso più semplice e il più comune per un blog. Niente adapter, niente main. Solo un wrangler.jsonc nella root.

{
  "name": "mio-sito-astro",
  "compatibility_date": "2026-10-14",
  "assets": {
    "directory": "./dist",
    "not_found_handling": "404-page"
  }
}

not_found_handling: "404-page" serve se hai una src/pages/404.astro. Senza, Workers non la usa da solo, come faceva Pages.

Poi build e deploy, con i comandi della guida Astro di Cloudflare:

npx astro build
npx wrangler deploy

Se il binding ASSETS ti resta nel file per abitudine, toglilo. La guida avverte che vale solo quando c'è uno script Worker indicato da main.

Caso 2: Astro con rendering on demand

Qui entra l'adapter. Se parti da Astro 6 o successivo, la guida di deploy di Astro indica questa configurazione:

{
  "main": "@astrojs/cloudflare/entrypoints/server",
  "name": "mio-sito-astro",
  "compatibility_date": "2026-10-14",
  "compatibility_flags": ["nodejs_compat", "global_fetch_strictly_public"],
  "assets": {
    "binding": "ASSETS",
    "directory": "./dist"
  },
  "observability": {
    "enabled": true
  }
}

Con Astro 6 il file Wrangler diventa perfino opzionale per i progetti semplici: se non hai binding da dichiarare, l'adapter genera una configurazione di default. Io lo terrei comunque nel repo. Un file versionato si legge in review, una configurazione generata no.

Se sei ancora su Astro 5 con adapter v12, la guida di Cloudflare usa "main": "./dist/_worker.js/index.js" e chiede un file public/.assetsignore con _worker.js e _routes.json. Senza, lo script del Worker finisce tra gli asset pubblici.

Il codice che cambia con Astro 6

La migrazione di piattaforma arriva spesso insieme all'aggiornamento di Astro. Le modifiche al codice sono di Astro, non di Cloudflare, ma le fai nello stesso momento.

Astro.locals.runtime non esiste più. Le variabili e i binding si importano dal runtime:

// prima
const { env } = Astro.locals.runtime;

// adesso
import { env } from 'cloudflare:workers';

L'oggetto cf si legge da Astro.request.cf. Il contesto di esecuzione, quello di waitUntil(), è in Astro.locals.cfContext. L'opzione workerEntryPoint dell'adapter è stata rimossa: un entrypoint custom si indica in main e si esporta come un Worker standard.

Due cambi meno visibili. astro dev ora gira su workerd, lo stesso runtime della produzione: le dipendenze CommonJS che prima passavano in sviluppo possono rompersi. E l'ambiente Cloudflare si sceglie al build, con CLOUDFLARE_ENV=staging astro build, non più al deploy con --env.

Cosa si rompe: header, redirect, variabili

Header e redirect sulle pagine SSR. _headers e _redirects funzionano anche su Workers, nella cartella public/. Ma la documentazione degli header è esplicita: non si applicano alle risposte generate dal Worker. Lo stesso vale per i redirect. Se una pagina è renderizzata on demand, CSP, X-Frame-Options o un 301 scritti lì non arrivano. Vanno impostati nel codice, o con Bulk Redirects per i redirect.

Limiti dei file. _redirects regge 2.000 redirect statici e 100 dinamici. _headers regge 100 regole. Se migri un sito vecchio con migliaia di URL storici, conta le righe prima.

Variabili di build. Su Pages le variabili impostate in dashboard valevano per build e runtime. Su Workers no. Se usi Workers Builds, le variabili che servono durante astro build vanno configurate nelle impostazioni della build. Quelle di runtime vanno in vars o come secret con wrangler secret put. Per lo sviluppo locale c'è .dev.vars, che resta fuori dal repo. Per il resto dei controlli su segreti e deploy vale la checklist del sito vibe-coded.

Ordine di risposta. Workers serve prima l'asset statico, se esiste, e solo dopo chiama il Worker. Se avevi un middleware di autenticazione o di log davanti a tutto, serve run_worker_first. Ogni richiesta che passa dal Worker conta come un'invocazione normale.

Trailing slash. Il default auto-trailing-slash risponde con un 307 verso la forma canonica. Controlla che i canonical e la sitemap usino la stessa forma, o ti ritrovi pagine doppie.

Il passaggio senza buio

Questo ordine, ricavato dalla guida di Cloudflare, tiene in piedi il sito vecchio fino all'ultimo.

  • Crea il Worker e deployalo su workers.dev, senza toccare il dominio.
  • Confronta le pagine critiche: home, un articolo, la 404, un redirect vecchio, gli header di una pagina SSR.
  • Collega il repo a Workers Builds e disattiva i deploy automatici del progetto Pages.
  • Sposta il dominio custom sul Worker.
  • Solo dopo giorni senza sorprese, cancella il progetto Pages con wrangler pages project delete.

Il comando per il controllo a secco esiste e conviene lanciarlo prima del primo deploy vero:

npx wrangler deploy --dry-run

Quando non ti conviene ancora

Ci sono casi in cui restare su Pages è la scelta onesta, almeno per ora.

  • Il dominio non è su Cloudflare. Pages accetta un dominio custom via CNAME anche fuori dalla zona Cloudflare. Workers no: servono i nameserver su Cloudflare.
  • Usi molto i controlli sui branch. La matrice di compatibilità segna i Branch Deploy Controls come supportati solo in parte su Workers.
  • Hai un sito Astro 5 statico che non tocchi da mesi. Funziona, non ha binding, non ha SSR. La migrazione ha senso quando aggiorni Astro, non prima.
  • Hai tante Pages Functions con routing a file. Si compilano in un Worker, ma Cloudflare stessa suggerisce di valutare un framework come HonoX se vuoi tenere quel modello.

Cosa guadagni spostandoti

Il guadagno vero non è il deploy. Sono le funzioni che su Pages non hai.

La matrice di compatibilità segna come solo Workers: Gradual Deployments, Workers Logs, Logpush, Tail Workers, Source Maps, Cron Triggers, consumer di Queues, Email Workers e il binding di Rate Limiting. Se ti serviva limitare un endpoint, ne ho scritto in rate limiting su Workers. E i Durable Objects si usano direttamente, senza un Worker separato da collegare.

Se il sito ha un database D1, controlla prima i backup di D1. I binding si ridichiarano nel file Wrangler. Conviene sapere dove sono i dati prima di spostare tutto.

Cosa conviene fare adesso

Apri il progetto e rispondi alle tre domande: statico o on demand, functions/ sì o no, Astro 5 o 6 e oltre. Poi scrivi il wrangler.jsonc del tuo caso, lancia wrangler deploy --dry-run e fai il primo deploy su workers.dev.

Prima di spostare il dominio, controlla header e redirect sulle pagine SSR. È lì che la migrazione fallisce in silenzio.

[ DOMANDE FREQUENTI ]

Domande frequenti

01Cloudflare Pages è deprecato?

La documentazione non lo dice. Cloudflare consiglia Workers per i progetti nuovi e offre una guida di migrazione per quelli esistenti. Per Astro il punto è un altro: l'adapter dalla v13 non supporta più Pages.

02Devo per forza usare l'adapter Cloudflare?

No, se il sito è tutto statico. Astro prerende le pagine e Workers serve la cartella dist. L'adapter serve solo per rendering on demand, server islands, actions e sessions.

03I miei _headers di sicurezza valgono ancora?

Sugli asset statici sì. Sulle pagine renderizzate dal Worker no: gli header vanno aggiunti nel codice, per esempio in un middleware Astro.

04Cambia il costo?

Secondo Cloudflare la struttura è simile: asset statici gratuiti, invocazioni al prezzo dei Workers. Cambia se attivi run_worker_first, perché ogni richiesta passa dal Worker e conta come invocazione.

Condividi