Edge Resolution and Cache
How Cloudflare Workers resolve aliases and cache deployed assets.
Odyn serves deployed code through a Cloudflare Worker running at the edge. The Worker resolves project identifiers and version aliases, fetches the built asset from R2, and returns it with appropriate cache headers. This page describes the resolution flow and caching behavior.
Request Flow
When a browser requests a CDN URL, the Cloudflare Worker handles the request in this order:
Browser request
|
v
Cloudflare Worker (edge)
|
+-- Parse URL: environment, project, version, file path
|
+-- Resolve project identifier (short ID, slug, or UUID)
|
+-- Resolve version:
| Staging: no version resolution needed (fixed R2 path)
| Production @latest: KV lookup for current version
| Production @N: KV lookup for pinned version timestamp
|
+-- Domain protection check (if configured)
|
+-- Fetch asset from R2
|
+-- Return response with cache headersProject Identifier Resolution
CDN URLs accept three project identifier formats, resolved in this priority:
- Short ID:
abc123— a compact identifier assigned to each project. - Owner/slug:
john/my-project— the owner's slug and the project's slug. - UUID:
f47ac10b-58cc-4372-a567-0e02b2c3d479— the full project ID.
The Worker checks each format against KV or the project registry to find the canonical project ID.
Version Resolution
Staging
Staging URLs resolve to a fixed R2 path:
projects/{projectId}/staging/bundle.{js|css}No version lookup is needed. The path is deterministic and overwritten on each staging deploy.
Production (Floating)
URLs without an explicit version resolve @latest:
https://cdn.odyn.dev/p/{project}/bundle.jsThe Worker reads the KV key {projectId}_prod_{assetType} to get the current version's timestamp, then constructs the R2 path:
projects/{projectId}/prod/bundle-{timestamp}.{js|css}Production (Pinned)
URLs with an explicit version number:
https://cdn.odyn.dev/p/{project}@42/bundle.jsThe Worker reads the KV key ver:{projectId}:prod:{versionNumber}:{assetType} to get the pinned version's timestamp.
Cache Behavior
| Environment | Cache-Control | Behavior |
|---|---|---|
| Staging | no-cache, no-store | Never cached. Every request fetches from R2. |
| Production (floating) | Short TTL | Cached at edge briefly. Updated when KV propagates. |
| Production (pinned) | public, max-age=31536000, immutable | Cached indefinitely. Content never changes. |
Staging: No Cache
Staging assets carry no-cache headers so that refreshing the browser always loads the latest deploy. This supports the rapid edit-deploy-verify cycle.
Production Floating: Short TTL
The floating alias depends on KV propagation. After a new deploy updates the KV pointer, edge nodes that cached the previous response continue serving it until their TTL expires. In practice, Cloudflare KV propagates globally within approximately 60 seconds.
Production Pinned: Immutable
Pinned URLs point to a specific version whose underlying R2 object never changes. Edge nodes and browsers can cache the response permanently. This is the most efficient caching strategy: zero revalidation, zero origin fetches after the first request.
KV Propagation
Cloudflare KV is eventually consistent. After a production deploy writes a new @latest pointer:
- The nearest edge node picks up the change almost immediately (typically under 1 second).
- Global propagation completes within approximately 60 seconds.
- During the propagation window, some edge nodes may serve the previous version.
This is acceptable for production workflows because:
- The previous version is still valid (it is the version that was live moments ago).
- Pinned URLs are not affected (they do not use the
@latestpointer). - Critical deployments can verify propagation by requesting the CDN URL from different regions.
Domain Protection at the Edge
If domain protection is enabled for a project, the Worker checks the Referer or Origin header against the project's allowed domain list before serving the asset. Domain rules are stored in KV and propagate with the same ~60 second delay.
localhost is always allowed regardless of the domain list. See Domain Protection.
Related
- CDN URL Patterns for the full URL anatomy.
- Immutable Bundles for why production assets are never overwritten.
- Version Pinning vs Floating Aliases for choosing between URL types.
- Domain Protection Blocking for troubleshooting blocked requests.