
ZMS
A headless block CMS that runs entirely at the edge: Cloudflare Workers, D1, R2, Pages and Workers AI. No servers, fast everywhere, and every publish is live worldwide right away.
The challenge
Client websites must be very fast and easy for clients to manage themselves. A publish has to be visible worldwide immediately, with no servers to maintain and one source of content blocks across many sites.
The solution
A headless CMS built entirely on the Cloudflare Developer Platform: a single API Worker as backend, D1 for content, R2 for media, Nuxt 4 on Pages for the editor and the sites, and Workers AI for search and recommendations.
The result
In production for client websites. The same stack was reused for the RDK Ready certification portal for Comcast / RDK, which de-risked phase one there.
Architecture
All traffic goes through one API Worker. The editor and the sites are separate Nuxt apps on Pages that talk to the Worker over service bindings.
Editor
Nuxt 4 · Pages
Client sites
Nuxt 4 · Pages
API Worker
Single backend
D1
Content · versions
R2
Media
Workers AI
Search · recs
Cache-Tag purge on publish
Simplified view of ZMS on the Cloudflare Developer Platform.
Key decisions
One API Worker
The only backend for delivery and authoring. One place for auth, validation and caching.
D1 with versioning
Content with draft, publish and rollback to any earlier version.
R2 for media
Images and files in object storage, without egress fees.
Cache-Tag invalidation
On publish, only the affected pages are purged from the edge cache.
@zms/blocks
The block contract as a versioned npm package, shared by the editor and every site.
Live preview
Drafts rendered in the real site through a signed token in an iframe.
Three auth domains
Cloudflare Access for staff, Worker sessions for members and service bindings between apps.
Workers AI
Smart search, product recommendations for cross- and upsell, and outreach.
Visual block editor
A Storyblok-style editor in which clients build pages themselves.
The hardest problem
Edge caching and instant publishing pull in opposite directions: you want to cache everything, yet a change must be live at once. So every page carries cache tags for the content on it. When a client publishes a block, the Worker purges exactly those tags, and the rest of the site keeps serving from cache.
Tech stack
- Cloudflare Workers
- D1
- R2
- Pages
- Workers AI
- Cache-Tags
- Service bindings
- Cloudflare Access
- Nuxt 4
- TypeScript
- npm package
Building at the edge?
Happy to think along about a fast, scalable architecture on Cloudflare.
Start a conversation