How to Use Cloudflare Pages with Astro: Complete Guide
Step-by-step guide to integrating Cloudflare Pages with your Astro website. Installation, configuration, and best practices.
Cloudflare is a serious contender for deploying Astro sites. You get unlimited bandwidth on the free tier, a global edge network spanning 300+ cities, and built-in support for on-demand rendering through Cloudflare Workers. If you want fast deploys with zero bandwidth bills, this is the way to go.
A note on naming before we start. Cloudflare has consolidated its full-stack hosting around Cloudflare Workers, and the official Cloudflare framework guide now creates new Astro projects with --platform=pages or as a Workers app depending on the flag you pass. The @astrojs/cloudflare adapter works for both. This guide covers the current adapter (version 13.x), which targets Astro 6.
This guide was checked against the official docs on 2026-05-29. Versions move fast, so always confirm the latest before you copy a config.
Prerequisites
- Node.js 20.19.1 or higher, or 22.12.0 or higher (the versions supported by Astro 6; Node 18 is no longer supported)
- An Astro project (
npm create astro@latest) - A Cloudflare account (free at cloudflare.com)
- Your project in a Git repository (GitHub or GitLab) if you want Git-connected deploys
Installation
Add the official Cloudflare adapter:
npx astro add cloudflare
This installs @astrojs/cloudflare and wires the adapter into your config. As of 2026-05-29 the current release is @astrojs/cloudflare@13.6.0. Its peer dependencies are astro@^6.3.0 and wrangler@^4.83.0, so make sure you are on Astro 6 before adding it. If you prefer to install by hand, run npm install @astrojs/cloudflare and add the adapter to your config yourself.
If you are scaffolding a brand new project, Cloudflare's own CLI sets everything up for you in one command:
npm create cloudflare@latest -- my-astro-app --framework=astro
This installs the adapter and the recommended Wrangler config automatically.
Configuration
After installation, your config will look like this:
// astro.config.mjs
import { defineConfig } from "astro/config";
import cloudflare from "@astrojs/cloudflare";
export default defineConfig({
adapter: cloudflare(),
});
Notice there is no output key. This is the most important change to be aware of if you are following an older tutorial. The output: 'hybrid' mode was removed in Astro 5, where static and hybrid were merged into a single default static mode. In Astro 6 the valid output values are only 'static' (the default) and 'server'.
With the default static output, every page is prerendered to HTML. The moment you add an adapter, you can opt any single page or endpoint into on-demand rendering by exporting prerender = false from it, with no output change required. The rest of the site stays static. Use output: 'server' only when you want on-demand rendering to be the default for the whole site and prefer to opt individual pages out instead.
For a purely static site you can still skip the adapter entirely. Just connect your repo to Cloudflare in the dashboard and set the build command to npm run build with the output directory as dist.
Deploying to Cloudflare
- Go to your Cloudflare dashboard and select Workers and Pages
- Click "Create" and connect your Git repository
- Set the build settings (these are Cloudflare's recommended values for Astro):
- Build command:
npm run build - Build output directory:
dist
- Build command:
- Add any environment variables your project needs
- Click "Save and Deploy"
Every push to your main branch triggers a production deployment. Pull requests get preview deployments automatically.
You can also deploy from the command line with Wrangler. Run npx wrangler deploy for a Workers project or npx wrangler pages deploy dist for a Pages project, after a fresh npm run build.
Basic Usage
With the adapter installed, server-rendered pages run on Cloudflare Workers at the edge:
---
// src/pages/api/data.ts
// This runs on Cloudflare Workers
export const prerender = false;
import type { APIRoute } from "astro";
export const GET: APIRoute = async ({ request }) => {
const url = new URL(request.url);
const country = request.headers.get("cf-ipcountry") || "unknown";
return new Response(
JSON.stringify({
message: `Hello from the edge!`,
country,
timestamp: Date.now(),
}),
{
headers: { "Content-Type": "application/json" },
}
);
};
Using Cloudflare Bindings
Cloudflare lets you access KV storage, D1 databases, and R2 object storage through bindings. This is the other big change in Astro 6: the old Astro.locals.runtime.env API was removed. You now import bindings directly from the cloudflare:workers module:
// src/pages/api/visits.ts
import type { APIRoute } from "astro";
import { env } from "cloudflare:workers";
export const prerender = false;
export const GET: APIRoute = async () => {
const kv = env.MY_KV_NAMESPACE;
const visits = parseInt((await kv.get("visits")) || "0") + 1;
await kv.put("visits", visits.toString());
return new Response(JSON.stringify({ visits }), {
headers: { "Content-Type": "application/json" },
});
};
The Cloudflare ExecutionContext, previously reached through Astro.locals.runtime.ctx, is now available as Astro.locals.cfContext. Plain environment variables also work through astro:env, for example import { MY_VARIABLE } from "astro:env/server".
The Wrangler configuration file is now optional for simple projects. When you do need bindings, the current adapter docs use wrangler.jsonc rather than the older wrangler.toml. Set compatibility_date to the date you create the file:
// wrangler.jsonc
{
"name": "my-astro-site",
"compatibility_date": "2026-05-29",
"main": "./dist/_worker.js/index.js",
"kv_namespaces": [
{
"binding": "MY_KV_NAMESPACE",
"id": "your-kv-namespace-id"
}
]
}
Production Tips
Take advantage of unlimited bandwidth. Unlike Vercel and Netlify, Cloudflare Pages has no bandwidth caps on the free tier. This makes it ideal for image-heavy or high-traffic sites.
Use Cloudflare R2 for media. Store images, videos, and downloads in R2 (zero egress fees) and serve them through a custom domain on Cloudflare. Way cheaper than S3.
Enable caching rules. Set up custom cache rules in the Cloudflare dashboard to cache API responses at the edge. This reduces Worker invocations and speeds up responses.
Use preview deployments for testing. Every branch gets its own URL. Test changes in a real production-like environment before merging.
Monitor with Cloudflare Analytics. Free built-in analytics show traffic, performance, and security metrics without any JavaScript trackers.
Alternatives to Consider
- Vercel if you need advanced features like ISR (Incremental Static Regeneration) or prefer the Vercel developer experience and ecosystem.
- Netlify if you want built-in form handling, identity management, and a wider plugin ecosystem.
- Railway if you need a backend with databases alongside your static site, all in one platform.
Common Errors and Fixes
output: 'hybrid' is not a valid config value. If you copy an old tutorial you will hit this. Hybrid was merged into the default static mode in Astro 5. Remove the output key entirely, or use output: 'server' if you want on-demand rendering by default. No other change is needed.
Astro.locals.runtime.env is undefined. This API was removed in Astro 6. Replace it with import { env } from "cloudflare:workers" and read bindings off env directly. If you used Astro.locals.runtime.ctx, switch to Astro.locals.cfContext.
import { env } from "cloudflare:workers" fails during build. There is a known interaction (tracked in withastro/astro issue 16553) where importing from cloudflare:workers breaks when a Node prerendering path is mixed with dynamic prerendered routes. The cloudflare: virtual module only resolves inside the Workers runtime, so keep those imports out of code paths that run during prerender, and confirm the page that uses bindings has export const prerender = false.
Hybrid sites behaving differently after upgrading to Astro 6. Several mixed static-plus-dynamic setups changed behavior on the Workers runtime (see withastro/astro issue 15237). Test with npm run dev and npm run preview, not just npm run build, because the Astro 6 dev server behavior changed significantly.
Build settings rejected by the dashboard. Cloudflare's recommended Astro settings are build command npm run build and build output directory dist. If Cloudflare auto-detected something else, set them manually.
Official Docs and Examples
- Astro Cloudflare adapter guide: https://docs.astro.build/en/guides/integrations-guide/cloudflare/
- Astro on-demand rendering (adapters,
prerender): https://docs.astro.build/en/guides/on-demand-rendering/ - Cloudflare's official Astro framework guide (Workers): https://developers.cloudflare.com/workers/framework-guides/web-apps/astro/
- Cloudflare's deploy-an-Astro-site guide (Pages): https://developers.cloudflare.com/pages/framework-guides/deploy-an-astro-site/
- Example repo: Cloudflare's official Astro blog starter template at https://github.com/cloudflare/templates/tree/main/astro-blog-starter-template
Wrapping Up
Cloudflare gives you an edge-first deployment platform with a generous free tier that is hard to beat. The official Astro adapter makes on-demand rendering seamless, and Cloudflare's binding system lets you add databases, KV storage, and object storage without leaving the ecosystem. The two things to remember on current versions are that output: 'hybrid' is gone and that bindings now come from import { env } from "cloudflare:workers".
Sources
All versions and facts below were checked on 2026-05-29.
@astrojs/cloudflareversion 13.6.0 and peer deps (astro@^6.3.0,wrangler@^4.83.0): https://registry.npmjs.org/@astrojs/cloudflare/latestastrolatest version 6.4.2: https://registry.npmjs.org/astro/latestwranglerlatest version 4.95.0: https://registry.npmjs.org/wrangler/latest- Adapter install command,
cloudflare:workersbindings,wrangler.jsonc, runtime context: https://docs.astro.build/en/guides/integrations-guide/cloudflare/ - Default
staticoutput, valid output values,prerender = falseopt-out: https://docs.astro.build/en/guides/on-demand-rendering/ output: 'hybrid'removed in Astro 5, static and hybrid merged: https://docs.astro.build/en/guides/upgrade-to/v5/- Cloudflare recommended build settings and create command: https://developers.cloudflare.com/pages/framework-guides/deploy-an-astro-site/
- Cloudflare Workers Astro guide,
wrangler.jsoncmainfield, blog starter template: https://developers.cloudflare.com/workers/framework-guides/web-apps/astro/ cloudflare:workersimport build failure with prerendering: https://github.com/withastro/astro/issues/16553- Hybrid sites behavior change on Workers in Astro 6: https://github.com/withastro/astro/issues/15237
Related Articles
How to Use Algolia with Astro: Complete Guide
Step-by-step guide to integrating Algolia with your Astro website.
How to Integrate Auth0 with Astro: Complete Guide
Step-by-step guide to integrating Auth0 with your Astro website. Setup, configuration, and best practices.
How to Use AWS Amplify with Astro: Complete Guide
Step-by-step guide to integrating AWS Amplify with your Astro website.