Astro's promise is deceptively simple: build fast, content-focused websites that send no JavaScript to the browser unless absolutely necessary. In practice, that promise is fulfilled by two primitives — island architecture and partial hydration. For a CDN, this is a fundamental shift. Instead of caching and delivering a monolithic SPA bundle, the edge must now serve a static HTML shell, a constellation of tiny, independently cacheable JavaScript islands, and a set of immutable hashed assets that rarely change. Done correctly, this model is the fastest way to deliver modern web experiences. Done poorly, it negates every benefit Astro provides.
This guide breaks down how to configure your CDN to exploit Astro's architecture at the edge — from cache-control design and hydration directives to edge middleware and HTTP/3 delivery.
Why Astro Changes the CDN Equation
Traditional frameworks like Next.js or Nuxt hydrate the entire page. Even if only a newsletter form is interactive, the browser downloads, parses, and executes JavaScript for the whole application. The CDN's job is straightforward: cache the HTML and the large bundle.
Astro inverts this. By default, every component — whether written in React, Vue, Svelte, Solid, or plain Astro — renders to static HTML at build time and ships zero client-side JavaScript. Interactivity is opt-in via a client:* directive. The result is a page composed of static HTML with isolated interactive islands floating inside it. Each island brings its own JavaScript, CSS, and data dependencies.
For the CDN, this means three distinct asset classes with different caching profiles:
- The Shell: The static HTML document. Highly cacheable, but must revalidate when content changes. Small, compressible, and perfect for edge caching with
stale-while-revalidate. - Islands: Hashed JavaScript chunks in
/_astro/. Immutable and versioned. Can be cached for a year at the edge and in the browser. - Shared Assets: Images, fonts, and CSS. Benefit enormously from CDN image optimization and modern formats like AVIF/WebP served via content negotiation at the edge.
Island Architecture: How the Edge Sees Your Page
An island is an interactive UI component that runs in isolation. Consider a marketing page with a static hero, a React-based product configurator, and a Vue comment widget. In Astro, only the configurator and comment widget become islands; everything else remains static HTML.
| Metric | Edge Processing | Origin Processing | Improvement |
|---|---|---|---|
| Latency (p50) | 8–15 ms | 120–300 ms | 15–20x faster |
| Cache Hit Ratio | 85–95% | N/A | Reduces origin load |
| TLS Handshake | 1–5 ms (nearby PoP) | 50–150 ms | 10–30x faster |
| Bandwidth Cost | $0.01–0.04/GB | $0.05–0.12/GB | 3–5x cheaper |
| Availability | 99.99% (multi-PoP) | 99.9% (single DC) | 10x fewer outages |
From the CDN's perspective, the browser request flow looks like this:
The CDN caches the static HTML shell with short SWR and immutable island chunks forever. Islands hydrate independently without blocking the shell.
This separation is what makes Astro ideal for edge delivery. The shell is cacheable everywhere, while islands are fetched only when their hydration trigger fires. Understanding this flow is critical for configuring your CDN architecture overview correctly.
Partial Hydration Directives and Edge Impact
Astro provides five client directives that control when island JavaScript loads and executes. Each has distinct CDN and performance implications. Choosing the wrong directive can force the CDN to deliver unnecessary JavaScript early, increasing Time to Interactive (TTI) and bandwidth.
| Directive | When It Hydrates | Edge Caching Strategy | Best For |
|---|---|---|---|
client:load |
Immediately on page load | High Priority Preload, immutable cache | Critical above-the-fold interactivity (cart, auth) |
client:idle |
When browser is idle (requestIdleCallback) | Immutable, low priority, deferred | Non-critical UI (search, theme toggle) |
client:visible |
When island enters viewport | Immutable, lazy-loaded, saves bandwidth | Below-the-fold widgets, comments, embeds |
client:media |
When media query matches | Immutable, conditional fetch | Mobile-only nav, desktop-only charts |
client:only |
Skips SSR, client-only render | No HTML caching benefit, JS-only | Browser-only APIs (maps, canvas) |
For CDN performance, prefer client:visible and client:idle for 80% of islands. They keep the initial document fully static and cacheable, while deferring JavaScript until after the shell has painted. Reserve client:load for islands that must be interactive before first paint. Avoid client:only unless you have no choice — it prevents the CDN from serving pre-rendered HTML for that component, forcing a client-side fetch.
Configuring Astro for Edge-Optimized Output
Your astro.config.mjs determines how the CDN should cache your site. For static sites, the output is straightforward:
Pair this with edge cache headers. For static HTML, use short TTL with background revalidation. For hashed assets, use immutable:
This pattern ensures the shell stays fresh without sacrificing edge hit ratio. The s-maxage directive controls CDN caching separately from browser caching, while stale-while-revalidate lets the edge serve stale content instantly while fetching a fresh copy in the background — critical for Astro blogs and marketing sites where content updates frequently but must remain fast.
Hybrid and SSR Islands at the Edge
Not every page can be fully static. Astro's output: 'hybrid' and output: 'server' modes let you pre-render most pages while server-rendering dynamic islands at the edge using middleware. This is where modern CDNs with edge compute (Cloudflare Workers, Fastly Compute, Vercel Edge Functions) shine.
In hybrid mode, the CDN serves static shells from cache and executes SSR islands at the edge, close to the user. The static shell still benefits from full edge caching, while the dynamic island is rendered per-request with edge data:
For true SSR islands, configure your edge adapter to set appropriate cache headers dynamically. Use Cache-Control: private for personalized content and public, s-maxage=30 for shared dynamic data. Leverage CDN cache invalidation with surrogate keys so you can purge only the affected shells when data changes, rather than the entire site.
Static Shell
Pre-rendered at build. Cached globally with SWR. Serves in <30ms from edge. No compute cost.
Edge SSR Island
Rendered at edge PoP on demand. Uses edge KV or fetch. Cached with short TTL + SWR.
Client Island
Static HTML + deferred JS. Immutable chunk cached forever. Hydrates only when triggered.
Caching, Compression, and Protocol Optimization
Astro's output is already lean, but the CDN can amplify those gains significantly.
Brotli and Zstd: Astro's HTML shells compress extremely well (70-80% reduction). Ensure your CDN serves Brotli (or Zstd where supported) for text/html and island JS. Pre-compressing at build time and serving via Content-Encoding negotiation reduces edge CPU.
HTTP/2 and HTTP/3: Islands load as multiple small chunks. HTTP/2 multiplexing and HTTP/3's QUIC protocol eliminate head-of-line blocking, letting islands load in parallel without waterfall delays. If your CDN supports HTTP/2, HTTP/3 and QUIC, enable it — the benefit is measurably larger for island architectures than for monolithic bundles.
Early Hints (103): Configure the CDN to send 103 Early Hints for critical island chunks and fonts. The browser can preconnect and preload islands before the full HTML arrives, shaving 100-200ms off LCP when using client:load for hero interactivity.
Image Optimization: Astro's <Image /> component generates responsive images, but the CDN should still handle format negotiation, resizing, and caching. Point your Astro image service to the CDN's image optimizer to avoid origin image processing and leverage CDN cost optimization through reduced origin egress.
Measuring Edge Performance for Islands
Track these metrics specifically for island architectures:
- Shell TTFB (edge HIT vs MISS): Should be <50ms HIT, <150ms MISS. Monitor cache hit ratio — aim for >95% for static shells.
- Island Hydration Cost: Measure Total Blocking Time (TBT) per island. An island that adds >50ms TBT should be deferred to
client:visibleorclient:idle. - JavaScript Payload: Astro's build report shows per-island JS size. Keep each island <20kB gzipped. The CDN should report edge bandwidth per
/_astro/*chunk. - LCP vs Hydration: Ensure LCP element is in the static shell, not inside an island. Islands should never block LCP.
Use Web Vitals from real users (CrUX or your RUM) segmented by edge PoP to identify regions where shell caching is cold. Warm the cache with synthetic requests after deploys.
Best Practices Checklist for Astro + CDN
- Set
output: 'static'by default; usehybridonly for dynamic routes. - Default to
client:visibleandclient:idle; audit everyclient:loadusage. - Cache shells with
s-maxage=300, stale-while-revalidate=600; cache/_astro/*as immutable. - Enable Brotli/Zstd, HTTP/3, and Early Hints at the edge.
- Use hashed filenames and surrogate keys for surgical performance and security purges.
- Keep LCP elements static; never place them inside a hydrated island.
- Deploy to edge compute for SSR islands; keep compute at the edge, not origin.
- Monitor per-island TBT and edge hit ratio after each deploy.
When these pieces align, Astro and the CDN become complementary: Astro minimizes what needs to be sent, and the CDN ensures what remains is delivered instantly from the edge. The result is a site that feels static in speed but remains fully interactive where it matters — the core promise of island architecture realized at global scale.
Frequently Asked Questions
How does a CDN handle Astro's island architecture differently from a traditional SPA?
Unlike SPAs where the CDN serves a single large JS bundle, Astro ships zero JS by default. The CDN caches the static HTML shell as a highly cacheable asset and treats each hydrated island as a separate, independently cached JS chunk. This allows edge nodes to serve the shell instantly (often in under 20ms) while islands load progressively only when their hydration trigger fires, dramatically reducing initial payload and TTI.
Which Astro hydration directive is best for CDN edge performance?
client:visible and client:idle are best for edge performance. They defer JavaScript execution until the island is visible or the main thread is idle, keeping the initial HTML fully static and cacheable at the edge. This reduces Total Blocking Time and saves bandwidth. Avoid client:load for non-critical islands as it forces immediate hydration and increases edge delivery cost.
Should I use SSR or static output for Astro on a CDN?
Use static output (output: 'static') for maximum CDN benefit — pages are pre-rendered at build time and cached globally with immutable assets for a year. Use hybrid or SSR (output: 'server' or 'hybrid') only for dynamic islands that require edge middleware, personalization, or authenticated data. For those, configure Cache-Control with short TTLs and stale-while-revalidate to balance freshness and hit ratio.
How do I invalidate CDN cache for Astro islands without purging everything?
Leverage Astro's content-hashed filenames for JS chunks (/_astro/Counter.abc123.js) — new builds generate new hashes, so old chunks remain cached but are no longer referenced. For HTML shells, use surrogate keys or cache tags at the edge and purge only the shells that import the changed island. For SSR islands, use short TTLs with SWR and tag-based invalidation to avoid full-site purges.