EmDash is slow (as of v0.9.0)

2026-05-06 07:48 (80 minutes ago)
EmDash is slow (as of v0.9.0)

Cloudflare launched a CMS called EmDash in April 2026. It's a full-stack CMS that runs on Astro + Cloudflare Workers + D1 + R2 and bills itself as the spiritual successor to WordPress. It's also AI-agent-first by design, so authoring a custom plugin with an LLM agent is unusually smooth.

I had high hopes when I tried it. It's noticeably slow in practice.

The default EmDash blog template — typical post-list landing page

▲ The site after applying EmDash's optional bundled demo data during setup. This is what the measurements below are taken against.

How slow

I deployed the default demo project (a typical blog with a post-list landing page) generated by create-emdash to Cloudflare Workers and measured response times. Plan: Cloudflare Workers Paid ($5/month).

=== Top page (with post list) ===
0.925s  TTFB=0.916s
0.505s  TTFB=0.501s
0.582s  TTFB=0.580s
0.486s  TTFB=0.484s
0.481s  TTFB=0.380s

=== /about page (text only, no images, minimal data fetching) ===
0.420s  TTFB=0.408s
0.464s  TTFB=0.458s
0.960s  TTFB=0.943s
0.511s  TTFB=0.507s
0.410s  TTFB=0.392s

The top page lands at 480–925 ms TTFB, and even a text-only /about page is 410–960 ms. Hit it more often and you'll catch a cold start that pushes it to 2–3 seconds.

Firefox DevTools network tab — a turtle warning icon next to the document request, with the tooltip "Slow server response time (880 ms). The recommended limit is 500 ms."

The browser is picking this up as well. Firefox's DevTools flags the document request with a turtle icon: "Slow server response time (880 ms). The recommended limit is 500 ms." The browser's own objective threshold rules it slow.

Comparison

For reference, here are some other sites I run.

Site Stack Measured TTFB
www.cyberneura.com Astro (SSG) + AWS Amplify Hosting / no DB 30 ms (160 ms cold)
www.ytyng.com SvelteKit (SSR) + Django Ninja API / PostgreSQL 70 ms
chat-attendant.cyberneura.net SvelteKit (SSG) + Cloudflare Pages / no DB 65 ms
emoji.ytyng.com SvelteKit (SSG) + Vercel / no DB 32 ms
emdash-test-01 (this post) EmDash 0.9.0 + Cloudflare Workers + D1 + R2 480–960 ms

The most directly comparable use case for EmDash is a blog site — that's exactly what www.ytyng.com (this site) is. Against it, EmDash is roughly 7× slower.

Against the static / SSG sites it's 20–30×.

"Is it just my setup?"

I checked. No, it isn't. It's structural to EmDash on Cloudflare Workers + D1.

A detailed third-party benchmark

shift64 — "I Bought the Domain Before I Ran the Test. EmDash Still Lost to WordPress."

EmDash WordPress Ratio
Server processing 543 ms 84 ms WordPress is 6.4× faster
Total TTFB 596 ms 136 ms

The author — who started out hoping EmDash would win — concludes (quoted):

An SEO professional reviewing crawl-stats charts blind classified the EmDash performance as needing to be "scrapped and rebuilt" (~1,300 ms zone), while the WordPress site landed in "normal, expected" territory.

After aggressive optimization, the gap narrowed only to 4.1× slower, still insufficient for recommendation.

The fundamental issue stems from architecture — D1 database round-trips at the edge create an unavoidable latency floor that optimization cannot overcome without platform-level changes to Cloudflare's infrastructure.

My measurements (596 ms vs his 596 ms) line up almost exactly, so this looks like a reproducible reality.

Other independent voices

  • Maciek Palmowski: EmDash, a fresh take on CMS — argues that EmDash doesn't actually target what WordPress users actually struggle with: performance, hosting cost, plugin bloat. EmDash's real focus is plugin security and AI-agent integration.
  • Hacker News thread #47602832 — not many direct performance complaints, but the overall mood is "interesting architecture, but we've heard this before."

Beware the contrary numbers

Some posts will tell you EmDash is blazing fast. Read carefully — they're measuring different things.

Trust the actual numbers from shift64 and your own probe — not the abstract latency claims.

What's slow

EmDash emits a Server-Timing header on every response. Here's the breakdown for one of my requests:

setup;dur=61          probe
rt;dur=89             runtime init total
  rt.db;dur=23        D1 migration check
  rt.plugins;dur=10   _plugin_state load
  rt.site;dur=12      site info options
  rt.market;dur=15    marketplace plugins
  rt.hooks;dur=29     exclusive hook resolution
render;dur=346        ← page render (D1 fetch for posts/media/menus)
mw;dur=496            ← total middleware (sum of the above)

The crucial bit: rt.* runs on every request. The migration check, plugin-state load, site-info read, and hook resolution are independent SELECTs against D1, and EmDash doesn't parallelize many of them. They stack up.

On top of that, render (346 ms) is Astro's page render plus EmDash's content fetch plus Portable Text rendering, with several more D1 queries (post list, menus, media references) inside.

Cloudflare D1 looks like SQLite from your code, but it's actually SQLite over the network at the edge. Each query is a 5–15 ms round-trip, and a few dozen of those is your 500 ms.

The shift64 benchmark concludes:

The fundamental issue stems from architecture — D1 database round-trips at the edge create an unavoidable latency floor that optimization cannot overcome without platform-level changes to Cloudflare's infrastructure.

Without platform-level changes (i.e. Cloudflare reworking D1's locality model), application-level optimization can't get past this floor.

Mitigations that exist

Not full fixes, but partial relief:

  1. Set Cache-Control: public, max-age=N on public pages → Cloudflare's CDN can cache and serve in single-digit milliseconds. Doesn't apply to authenticated admin / preview / dynamic APIs.
  2. D1 Sessions API (read replicas) — set session: "auto" in astro.config.mjs. Helps if a replica is geographically near the request, otherwise marginal.
  3. Call Astro.cache.set(cacheHint) on pages — listed as a project rule in EmDash's template CLAUDE.md.
  4. Deploy on Node.js + local SQLite (containers) — drops to ~85 ms TTFB but you give up the Workers value proposition.

Does the $5 plan fix it?

No. Workers Paid ($5/month) only changes CPU time limits (Free 10 ms → Paid 30 / 50 ms) and the billing model. It does not change the per-request count of D1 round-trips or the edge latency.

It helps for CPU-heavy workloads (image transforms etc.), but EmDash's request flow is I/O-dominated, so the user-facing TTFB barely moves.

What about the EmDash project itself?

Searching emdash-cms/emdash issues for performance keywords turns up nothing dedicated. The team's stated focus is plugin security and AI-agent-first, not raw speed.

In other words, there's no visible push for the kind of architectural rework that would actually fix this.

Verdict

Expectation Reality
It's Cloudflare's flagship CMS — must be fast Structurally 6× slower than WordPress
Workers cold start is <5 ms — instant Worker boots fast, but D1 RPCs stack up
Cache-Control will solve it Only for the static slice; falls apart on admin / preview / dynamic
Upgrading to Workers Paid ($5) will help Unrelated; only loosens CPU caps

For now, adopting EmDash for production is a meaningful risk.

For hands-on, hobby, or experiments around AI-agent–driven CMS authoring, it's fine — that's the genuine strength here, and speed is secondary in those contexts.

For a traffic-bearing production site, holding off is the safer call. As you add features, lifecycle hooks, and plugins, the trajectory is monotonically slower — barring framework-level rework.

The realistic path forward is waiting for the EmDash team or Cloudflare to revisit D1's locality model (e.g. embedding a SQLite-shaped layer inside the application Worker itself).

Please rate this article
Currently unrated
The author runs the application development company Cyberneura.
We look forward to discussing your development needs.

Categories

Archive