---
title: "EmDash and Cloudflare: How the Stack Works"
description: "A builder's guide to how EmDash uses Cloudflare Workers, D1, R2, and Pages. What each service does, how they connect, and why this architecture matters."
article_type: sub-pillar
canonical: https://dashstro.com/learn/emdash-cloudflare-stack
---
:::bluf
EmDash runs on four Cloudflare services: Workers (compute), D1 (database), R2 (media), Pages (deployment). There's no origin server — the entire request/response cycle stays on Cloudflare's edge network, which is why cached pages land in 10-30ms. The trade-off is Cloudflare dependency; the payoff is zero server maintenance and a free tier that covers most content sites.
:::

EmDash is the first CMS designed from the ground up for Cloudflare's edge platform. Not ported to it, not adapted for it — built on it. Understanding how the stack fits together helps you make better decisions about your site architecture. I've been building on this stack since launch day, so this is from hands-on experience, not documentation.

## The four services

EmDash uses four Cloudflare services. Each handles one concern:

| Service | Role | Free tier |
| --- | --- | --- |
| Workers | Server-side compute — runs your Astro pages, API endpoints, admin panel, and plugins | 100,000 requests/day |
| D1 | Serverless SQLite database — stores content, users, taxonomies, menus, settings | 5M rows read/day, 100K rows written/day |
| R2 | S3-compatible object storage — images, documents, and file uploads with no egress fees | 10 GB storage, no egress fees |
| Pages | Git-connected hosting — builds on push, deploys globally, handles SSL and custom domains | 500 builds/month, unlimited sites |

- Workers — server-side compute. Your Astro pages, API endpoints, admin panel, and plugin runtime all execute inside Workers. Think of it as your application server, except it runs in 300+ data centers simultaneously.
- D1 — the database. Cloudflare's serverless SQLite. Your content, users, taxonomy terms, menus, settings, and plugin data all live here. It's relational, supports full SQL, and replicates globally.
- R2 — media storage. S3-compatible object storage for images, documents, and file uploads. No egress fees, which matters if you serve a lot of media.
- Pages — hosting and deployment. Connects to your Git repo, builds on push, deploys globally. Handles SSL, custom domains, and preview deployments automatically.

## How a page request flows

When someone visits your EmDash site, here's what happens:

The request hits the nearest Cloudflare data center. The Worker (your Astro application) executes locally in that data center. It queries D1 for content and resolves media URLs from R2. Astro renders the page server-side and returns HTML. The entire round-trip stays on Cloudflare's network — there's no origin server to reach.

:::pullquote
The entire round-trip stays on Cloudflare's network — there's no origin server to reach.
:::

Cached pages skip the Worker entirely and serve from Cloudflare's edge cache in 10-30ms. Cache invalidation happens automatically when content is published through the admin panel — EmDash uses cacheHint tokens that tell Cloudflare exactly what to invalidate.

## D1: serverless SQLite at the edge

D1 is SQLite running on Cloudflare's network. EmDash creates tables for each content collection (ec_learn, ec_docs, ec_pages, etc.), plus system tables for users, menus, taxonomies, search indices, and plugin storage.

Content is stored as structured fields — title, description, and custom fields are regular columns. Rich text (Portable Text) is stored as JSON. This gives you the query performance of SQL with the flexibility of structured content.

During local development, EmDash uses Miniflare to simulate D1 with a local SQLite file. Your code is identical in dev and production — no environment-specific adapters or mock services.

## R2: media without egress fees

R2 stores your media files. When you upload an image through the admin panel, it goes to R2. When a page references that image, the Image component generates the URL and Cloudflare serves it from the edge cache.

The killer feature of R2 is zero egress fees. AWS S3 charges you to serve files to visitors. R2 doesn't. For media-heavy sites, this can be a significant cost difference. Cloudflare can do this because they own the network — serving files from their own cache costs them almost nothing.

## Workers: the application runtime

Workers is where your Astro application runs. EmDash compiles your site into a Worker that handles page rendering, API endpoints, the admin panel, and plugin execution.

The plugin sandboxing is worth understanding. Plugins run in separate Worker isolates, not in the same runtime as your application. Each plugin declares capabilities in a manifest and only receives the APIs it requested. A plugin that says it needs "read content" cannot access media storage or user data. This is enforced at the runtime level, not by convention.

## Why this architecture matters

Three things set this apart from traditional CMS hosting:

- No single point of failure. There's no origin server that can go down. Your site runs in hundreds of locations simultaneously.
- Scale to zero. When nobody visits, you pay nothing. Workers only charge for requests processed. A traditional server runs (and costs money) 24/7 whether anyone visits or not.
- Security by design. Plugin sandboxing, passkey authentication, and no ambient database access aren't features — they're consequences of the architecture. You can't accidentally create a security hole because the platform doesn't allow it.

The trade-off is Cloudflare dependency. Your site, database, and media are all on one platform. Cloudflare is unlikely to go anywhere, but it's worth acknowledging. EmDash can't run on AWS or Vercel today. That may change, but right now it's Cloudflare or nothing.
