EmDash is slow (as of v0.9.0)

2026-05-06 07:48 (5 months ago)
Turtle Badge
Play a song themed on this article

I tried EmDash, a CMS that Cloudflare announced in April 2026. It is a full-stack CMS that runs on Astro + Cloudflare Workers + D1 + R2, and it claims to be the "spiritual successor to WordPress". It has an AI agent first design, so it works well with agents, and writing your own plugin is relatively smooth too.

I had expectations when I tried it, but it feels clearly slow.

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

▲ A site with the demo data that you can install when building an EmDash site. This is what I measured.

How slow

I deployed the default demo project generated by create-emdash (a typical blog with a post list on the top page) to Cloudflare Workers and measured the response time. The plan is 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

480ms to 925ms for the top page, and 410ms to 960ms even for the text-only about page. With more attempts, some requests hit a cold start and reach 2 to 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 also detects this slowness correctly. Firefox's developer tools show a turtle icon warning next to the document request. The text is "Slow server response time (880 ms). The recommended limit is 500 ms.", so it is judged clearly slow by the browser's objective standard as well.

Comparison

For reference, here are measurements of other sites I run.

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

The one that can be compared with EmDash as a use case is www.ytyng.com (this site), which is a blog. Compared with it, EmDash is about 5 times slower.

Compared with the SSG (static) sites, it is 20 to 30 times slower.

"Is it just my setup?"

I suspected that and looked for other people's reports. It is not just my setup. It is a structural property of 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 times faster
Total TTFB 596 ms 136 ms

I quote the conclusion of the author (who was favorable to EmDash and had expectations for it).

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.

This almost matches my own measurement (596ms vs 596ms), so the numbers can be considered reproducible.

Other independent voices

  • Maciek Palmowski: EmDash a fresh take on CMS points out that "EmDash does not even target what WordPress users really struggle with: performance / hosting cost / plugin bloat". EmDash's main focus is AI agent first and plugin security
  • Hacker News thread (47602832) has few direct mentions of performance, but the overall tone of the reaction is "the architecture is interesting, but we have heard this story before"

Beware the contrary numbers

On the other hand, some articles say "EmDash is blazing fast", but if you read them carefully, the numbers are taken in a different way.

Don't be misled by these. It is better to trust the shift64.com numbers, which are based on real measurements.

What's slow

The Server-Timing header that EmDash outputs shows the breakdown. For the request I measured this time, it was as follows.

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)

What matters here is that the rt.* runtime init runs on every request. The migration check, the plugin state load, site info, and hook resolution are all independent SELECTs against D1. In many places EmDash does not parallelize them, so they add up.

In addition, the 346ms of render is Astro's page render + EmDash's content fetch + Portable Text rendering. Here too, the post list, menus, related media and so on are fetched from D1 with multiple queries.

Cloudflare's D1 is SQLite from the code's point of view, but in reality it is a SQLite server across the edge network. Each query takes a 5 to 15ms round trip, and these add up to the 500ms level.

According to shift64's benchmark:

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.

Unless the platform side (Cloudflare's D1) is reworked, application-layer optimization cannot get past this.

Mitigations that exist

They do not solve it completely, but there are some mitigations.

  1. Add Cache-Control: public, max-age=N to public pages → If it becomes a Cloudflare CDN cache hit, it is at the millisecond level. But it cannot be used for admin / preview / dynamic APIs where authentication is involved
  2. D1 Sessions API (read replica). It is enabled by putting session: "auto" in astro.config.mjs. But the effect is small unless a read replica is geographically close
  3. Call Astro's Astro.cache.set(cacheHint) in pages. This rule is also written in the CLAUDE.md of the EmDash template
  4. Deploy to Node.js + local SQLite (containers). It improves dramatically to ~85ms TTFB, but you lose the benefits of Workers

Does the $5 plan fix it?

No. What changes with Workers Paid ($5/month) is only the CPU time limit (Free 10ms → Paid 30/50ms) and the billing model. It has nothing to do with the number of D1 round trips per request or the latency across the edge.

If CPU-heavy processing (image conversion, etc.) occurs, there is a difference, but EmDash's main flow is mostly I/O, so upgrading to $5 hardly changes the TTFB you experience.

What about the EmDash project itself?

Searching the Issues of emdash-cms/emdash with performance-related keywords, I find no open issue dedicated to performance. The core team does not make speed a main goal (the official tagline is Plugin Security and AI agent-first).

In other words, at this point there is no sign that a fundamental improvement on the framework side is being actively pursued.

At this stage, I feel that there are many risk factors in adopting it for production.

For hands-on work, for play, or as an experiment in AI agent integration, there is no problem at all. Being able to operate a CMS programmatically from an AI agent is a real strength of EmDash, so for that use, speed can come second.

However, for a production site where traffic is expected, putting adoption on hold for now is the reasonable choice. As you add more features on the app side, lifecycle hooks and plugin loading increase, and it can only go in the direction of getting even slower (unless a fundamental improvement to the framework comes in).

I think the realistic option is to wait for the EmDash team or Cloudflare to rework the D1 architecture (for example, a form that embeds SQLite inside the app Worker).

Please rate this article (No signup or login required)
Currently unrated

Related posts

The author runs the application development company Cyberneura.
We look forward to discussing your development needs.

Categories

Archive