Static asset caching
The SDK caches static files on Cloudflare's edge. Hashed build files can be reused across deploys; other files use cache keys tied to each deployment.
On this pageSee how hashed and non-hashed files are cached · Set cache headers for assets · Know what changes after a deploy
Hashed assets
Files in Vite's build.assetsDir (default assets/) carry a content hash in the name, such as assets/app-Ab3xK9.js. The name changes whenever the content changes. That makes them immutable, so they get long-lived caching:
Cache-Control: public, max-age=31536000, immutableBrowsers and the edge can cache these files for one year and reuse them across deploys.
If you customize build.assetsDir, the SDK detects it. It applies immutable caching to that directory:
// vite.config.ts
export default defineConfig({
build: {
assetsDir: 'static', // hashed assets go to dist/client/static/
},
});If build.assetsDir is "", hashed files live at the root. The SDK then skips the optimization. It cannot tell hashed from non-hashed files by directory.
Supported meta-frameworks use their own asset directories automatically.
Native Cloudflare deployments
With void deploy --platform cloudflare, generated JavaScript bundles with content fingerprints receive immutable caching. Files from public/ and build outputs with stable names keep normal revalidation, even inside the assets directory. CSS and other assets keep Cloudflare's default or your configured Cache-Control.
Use Custom Headers to choose a cache policy for other files. Apply immutable caching only to URLs that change whenever their content changes.
Non-hashed assets
Other static files, such as index.html and favicon.ico, are cached until the next deploy. No manual purge is needed.
Cache-Control: public, s-maxage=31536000, max-age=0, must-revalidateBrowsers revalidate these files on each request.
What gets cached:
- All
GETrequests for non-SSR projects such as SPAs and static sites - GET requests with file extensions (
.ico,.png,.css, etc.) in SSR projects
What does NOT get cached:
/api/*routes, which always hit the worker- SSR-rendered pages (paths without file extensions in SSR projects)
- Non-GET requests
- Requests carrying
Cookie,Authorization, orCf-Access-Jwt-Assertioncredentials - Responses other than a complete
200
Opting out
Your worker may serve dynamic content at a static-looking URL, such as a generated /avatar.jpg. To stop caching, send Cache-Control: private or Cache-Control: no-store. Any response with private, no-store or no-cache in Cache-Control, or with Set-Cookie, bypasses the edge cache.
ETags and 304 not modified
Static assets include an ETag header. When a browser revalidates an unchanged file, the SDK returns 304 Not Modified. The file is not downloaded again. No configuration is needed.
Custom headers
To override caching headers or add your own on any asset path, use Custom Headers.
Navigation and middleware
The SDK serves static files directly unless app code must handle the request first. API requests reach your Worker. Apps with middleware, routes outside /api, Pages, or SSR run application code before serving fallback HTML.
SPAs serve index.html for unmatched navigation, so client-side routing works. This step sets routing.notFound for a static site with a 404.html page.
import { defineConfig } from 'void/config';
export default defineConfig({
routing: { notFound: '404-page' },
});Choose single-page-application, 404-page, or none. These settings do not change which requests reach middleware and API handlers. Intentional API 404 responses keep their status and body.
SvelteKit, Nuxt, Analog, and Astro handle their own error pages and ignore routing.notFound. For direct Cloudflare deployment with TanStack Start, React Router, or vinext, configure the asset binding, directory, and routing policy through the framework's Cloudflare config.
API routes and SSR pages
API responses and SSR pages are not cached as static assets. Use Revalidation to cache public rendered pages.