DEV Community

Cover image for Astro + Cloudflare Pages: 3 Deploy Bugs You'll Probably Hit
Mike
Mike

Posted on

Astro + Cloudflare Pages: 3 Deploy Bugs You'll Probably Hit

I've been building a static Astro site on Cloudflare Pages over the last few weeks. Sharing the 3 deployment bugs that cost me the most time, in case they save anyone else the same loop.

Setup

Astro 5 + Cloudflare Pages + Tailwind 4. Content lives in a few JSON files; each page is a dynamic route mapped over the data. Free-tier hosting, no backend. Standard static-first stack.

Bug 1: Trailing-slash 307 chain

I started with trailingSlash: 'never' in Astro config. Build output went to dist/foo/index.html. Result: Astro emitted canonical tags as /foo (no slash), but Cloudflare Pages served /foo/ (auto-adding the slash via 307). Google Search Console flagged pages as "Redirect error" because the canonical URL pointed at a redirect chain instead of a real 200.

I first tried build.format: 'file' to get flat dist/foo.html output, hoping that would bypass the trailing slash. That made it worse — Cloudflare still 307-stripped, but now to a non-existent .html file → 404.

Fix: stop fighting the platform.

js
// astro.config.mjs
export default defineConfig({
trailingSlash: 'always',
// ...
});

trailingSlash: 'always' plus default directory build aligns the canonical URL with what Pages actually serves. The redirect errors resolved on next re-crawl.

Bug 2: _redirects rejected at deploy

I tried to do a www → apex 301 in public/_redirects:

https://www.example.com/* https://example.com/:splat 301!

Cloudflare rejected the deploy with three validation errors:


Line 13: Only relative URLs are allowed.
Line 22: Duplicate rule for path /foo.
Line 23: Duplicate rule for path /bar.

Pages tightened _redirects validation — absolute-URL sources aren't accepted anymore. The duplicate errors were because Astro's own redirects config in astro.config.mjs generates HTML meta-refresh files that Pages parses as implicit redirect rules — conflicting with my explicit ones.

Fix: delete _redirects entirely. Use a Cloudflare Redirect Rule from the dashboard for cross-host 301s (Wildcard pattern, Dynamic destination with ${1} to preserve the path). Astro's HTML-redirect generation handles the in-config aliases on its own.

Bug 3: Asset manifest staleness across deploys

After switching between build.format: 'file' and back to directory output, some nested paths started returning 308 → no-slash → 404. Even brand-new URLs that had never been deployed before. Local build output was correct — the live response was stripping the trailing slash on specific nested patterns.

Turned out to be a stale asset manifest from the previous build mode. Pages was still serving 308s for old .html file paths even though those files no longer existed in the current deploy.

Fix: push any commit that triggers a full Pages rebuild — the manifest regenerates cleanly. If you don't have a pending change, an empty commit works:

sh
git commit --allow-empty -m "force rebuild"
git push

Lessons

  • Pick a URL convention (slash or no slash) before deploying to Pages. Switching mid-flight leaves cached redirects that take a full rebuild to clear.
  • _redirects is more restricted than the docs suggest. Use dashboard Redirect Rules for anything cross-host.
  • GSC's "Redirect error" category is the canary for canonical / serve-URL mismatches. Worth checking weekly.

Build-in-public log lives on my site if you want to follow along.

Top comments (0)