Astro integration for client-side dynamic routes with Cloudflare Pages
npm install astro-cloudflare-pages-staticAn Astro integration for client-side dynamic routes with Cloudflare Pages.
Without this integration, Astro dynamic routes are only supported two scenarios:
1. Itemizing every path using getStaticPaths()
2. Using server-side rendering without itemizing every path
This integration offers a third option: Using static rendering without itemizing every path.
This enables lightweight routing similar to SvelteKit's adapter-static, serving the same HTML shell for dynamic paths and handling content client-side.
By making use of Cloudflare Pages Functions exclusively for lightweight routing, cost, execution time and complexity remains minimal.
Compared to full SSR, this approach is significantly cheaper (invoking functions only for routing) and faster (sub-1ms latency for hot starts), making it ideal for SaaS dashboards and other dynamic routes that can tolerate loading progressively.
All pages in your Astro project remain rendered statically, while benefiting from some server-side rendering features (such as dynamic path pre-rendering).
- 🚀 Automatic Route Detection - Uses [standard Astro [param] syntax](https://docs.astro.build/en/guides/routing/#on-demand-dynamic-routes)
- 📦 Zero Config - Works out of the box
- 🪄 Auto-Injection - Automatically handles getStaticPaths for you
- 🎨 Real Astro Pages - Your dynamic routes are actual .astro files with full styling and pre-rendering
- 🔧 Client-Side First - Serves pre-rendered HTML shell, you handle data fetching in the browser
- 🌐 Dev Mode Support - No Wrangler needed during development
- ⚡ Lightweight - Generates minimal Cloudflare Worker code (typically <1ms execution time)
``bash`
npm install astro-cloudflare-pages-static
`js
// astro.config.mjs
import { defineConfig } from 'astro';
import cloudflare from "@astrojs/cloudflare";
import cloudflarePagesStatic from 'astro-cloudflare-pages-static';
export default defineConfig({
output: 'static',
adapter: cloudflare(), // optional
integrations: [
cloudflarePagesStatic()
]
});
`
Just like using Astro with server-side rendering, creating routes is as simple as naming a file or folder [slug].astro or [...slug].astro.
You can access route parameters using Astro.params:
`astro
---
import Layout from '../../layouts/Layout.astro';
const { id } = Astro.params;
---
Loading user {id}...}>
`
`bash`
npm run buildDeploy dist/ to Cloudflare Pages
This integration is designed for static output with client-side routing.
When used with @astrojs/cloudflare adapter output: 'static' configuration must be used.
If you are using server-side rendering (output: 'server') this integration is redundant, dynamic pages already work for you.
This integration works cheaply by using simple regex string replacement.
While cost effective, only light content sanitation is done (escaping basic HTML tokens).
Use caution when working with parameter values as they are user generated content, do not use them for innerHTML without sanitizing first.
`typescript`
interface DynamicRoutesOptions {
// Additional paths to exclude from routing
excludePaths?: string[];
}
You can find a complete working example in the examples/ directory.
`bash`
cd examples
npm install
npm run dev
If you have an existing _worker.js in your project, this integration will automatically chain it in the dist directory.
This allows you to combine multiple Cloudflare Workers.
This behavior is experimental, if you have issues open an issue containing a minimal reproduction.
Additional paths to avoid running Cloudflare Pages Functions:
`javascript``
cloudflarePagesStatic({
excludePaths: ['/api/', '/admin/']
})
This integration relies on string replacement of an "encoded" static parameter stub at the edge.
If you modify the parameter string in your pre-rendered component logic, the parameter will not be correctly replaced until client-side hydration completes.
To avoid this, delay manipulation of the parameter value until client-side render.
Or better yet, use CSS to visually manipulate the parameter value while maintaining the full source.