Cloudflare's serverless CMS EmDash is now in beta as a WordPress successor
Contents
WordPress is now 24 years old. It powers more than 40% of the internet, but its plugin security problems have only gotten worse. Cloudflare’s beta release on April 2, EmDash, tries to solve that structural problem by rethinking the architecture itself. It is a full-stack serverless CMS built on Astro 6.0, and it is open source under the MIT license.
It is called a “WordPress successor,” but that is only partly fair. WordPress has 24 years of ecosystem depth, while EmDash is still at v0.1.0. On the other hand, there are areas where WordPress simply cannot fix its own structural problems and EmDash is starting from a clean design. I looked at the strengths and weaknesses side by side.
Overall Comparison
| Dimension | WordPress | EmDash | Advantage |
|---|---|---|---|
| Language | PHP | TypeScript | Depends |
| Theme engine | Custom template system (PHP) | Astro 6.0 | Depends |
| Data store | MySQL / MariaDB | D1 (SQLite-compatible) | WordPress (proven) |
| Hosting | Anywhere, even cheap shared hosting | Cloudflare Workers or any environment that runs workerd | WordPress (more options) |
| Plugins | 59,000+ | Ecosystem still starting | WordPress (huge lead) |
| Themes | 12,000+ in the official directory | A few official themes so far | WordPress (huge lead) |
| Plugin isolation | None. Full access | Fully isolated in V8 isolates | EmDash (structural win) |
| Admin UI | Mature and usable for non-engineers | Basic, still evolving | WordPress (maturity) |
| Community | Huge. Lots of Japanese resources too | Starting from zero | WordPress (huge lead) |
| License | GPLv2 | MIT | EmDash (freedom) |
| Initial cost | Free to a few hundred yen per month | Runs on Cloudflare’s free tier | Tie |
| Scalability | Needs extra servers or CDN layers | Runs at the edge and auto-scales | EmDash |
| Authentication | Passwords, with 2FA via plugins | Passkeys by default | EmDash |
| Content monetization | Plugins like WooCommerce | x402 built in | EmDash (simpler) |
| AI agent integration | REST API as an add-on | MCP server built in | EmDash |
| Multilingual support | Plugins like WPML and Polylang | Astro i18n + edge routing built in | Depends |
The things EmDash wins on are architectural. WordPress cannot easily catch up there. The things WordPress wins on are ecosystem depth and operational maturity, and EmDash will need years to narrow that gap.
Where EmDash Wins Structurally
WordPress Plugin Security Problems
WordPress plugins get full access to the site’s database and filesystem the moment they are installed. There is no sandbox and no meaningful privilege separation. Through add_action and add_filter, a plugin can hook into anything in WordPress, and through $wpdb it can run raw SQL. In practice, installing a plugin has long been close to giving a stranger root on the server.
graph LR
subgraph WordPress plugin model
P[Plugin] -->|add_action/add_filter| H[All hooks]
P -->|$wpdb| DB[(MySQL)]
P -->|file_get_contents etc.| FS[Filesystem]
P -->|wp_remote_get etc.| NET[External network]
end
The damage is visible in the numbers.
| Metric | Value |
|---|---|
| New vulnerabilities in the WordPress ecosystem in 2025 | 10,794 (about 30 per day) |
| Share caused by plugins | 96% |
| Vulnerabilities exploitable without authentication | More than 43% |
| High-severity vulnerabilities in 2025 | More than the previous two years combined |
| Developers who did not fix bugs even after learning about them | 52% |
According to Patchstack’s report, the 2026 CVE total is expected to rise another 15% year over year to about 55,000. More than 800 plugins are waiting in the WordPress.org review queue, and processing takes at least two weeks.
That does not mean WordPress is uniquely dangerous. If you have 59,000 plugins, you should expect a lot of vulnerabilities. The real problem is the architecture: one vulnerable plugin can endanger the whole site. WordPress cannot easily fix that after the fact, because running plugins in the same PHP process is part of the platform’s core design.
EmDash runs each plugin as an isolated Dynamic Worker inside its own V8 isolate.
What Is a V8 Isolate?
V8 is the JavaScript engine used by Chrome and Node.js. An isolate is an independent execution environment inside V8. Each isolate has its own heap and cannot access the memory of another isolate. Unlike container virtualization, this has almost no OS-level overhead, so startup happens in milliseconds. Cloudflare says it is 100x faster than containers.
Comparing the Isolation Model
| Aspect | WordPress | EmDash |
|---|---|---|
| Plugin execution environment | Same PHP process | Separate V8 isolate per plugin |
| Memory space | Shared | Fully isolated |
| DB access | Raw SQL through $wpdb | API only. No raw SQL |
| Filesystem | Full access | No access |
| Network | Unrestricted | No network unless the host is explicitly allowed |
| Permission model | Full delegation (install = full access) | Capability-based (only declared permissions) |
| Blast radius of a vulnerable plugin | Whole site: DB, files, and other plugins | Only the permissions granted to that plugin |
In WordPress, one compromised plugin can expose the entire site, the database, the filesystem, and even other sites on the same server. In EmDash, the damage is supposed to stop at the permissions the plugin was granted.
Cloudflare Workers adds multiple layers of defense:
| Layer | Protection |
|---|---|
| V8 isolate | Complete memory isolation |
| Process sandbox | Linux namespaces + seccomp to block filesystem and network access |
| Cordon separation | Separate process groups by trust level; free-tier and enterprise workloads do not share a group |
| Hardware protection | Random memory protection keys protect heap data; even with a bug, 92% of cases trap at the hardware layer |
| Timing-attack protection | Date.now() is fixed while code runs, and there is no multithreading, so side-channel attacks are structurally limited |
WordPress cannot bolt this on after the fact. PHP’s process model does not allow this sort of plugin isolation. A WAF or malware scanner can help from the outside, but it cannot stop a plugin from misbehaving internally.
Capability-Based Access Control
EmDash plugins only receive the capabilities declared in their manifest. There is no direct database or filesystem access.
import { definePlugin } from "emdash";
export default () => definePlugin({
id: "notify-on-publish",
version: "1.0.0",
capabilities: ["read:content", "email:send"],
hooks: {
"content:afterSave": async (event, ctx) => {
// ctx only has the read:content and email:send capabilities
// No direct DB access or raw network access is possible
}
}
});
WordPress has no way to tell users what a plugin can do at install time. Unlike an Android app that asks for permissions up front, a WordPress plugin silently takes everything. EmDash’s model is closer to Android permissions: users can see what they are allowing.
That said, capability-based access has limits. A plugin with read:content can still read everything in that scope. Whether EmDash can eventually support finer-grained controls like “only this article” or “only this field” is still unclear from the beta docs.
graph LR
subgraph WordPress
WP_Plugin[Plugin] -->|Full access| WP_DB[(Database)]
WP_Plugin -->|Full access| WP_FS[Filesystem]
WP_Plugin -->|Unrestricted| WP_Net[External network]
end
subgraph EmDash
ED_Plugin[Plugin<br/>Dynamic Worker] -->|read:content only| ED_DB[(D1)]
ED_Plugin -->|email:send only| ED_Email[Mail API]
ED_Plugin -.-x|No access| ED_FS[Filesystem]
ED_Plugin -.-x|No access| ED_Net[External network]
end
Performance and Scalability
WordPress is the classic PHP + MySQL server-side stack. Every request generates the full HTML page on the server and sends queries to MySQL. To speed that up, you usually need page-cache plugins, a CDN, and sometimes Varnish or Redis at the infrastructure layer.
EmDash runs on Cloudflare Workers, so requests are processed at the edge, close to the user. There is no need to build a separate CDN or cache layer. D1 is also at the edge, so database latency stays low.
graph TD
A[Browser] -->|Request| B[Cloudflare Workers<br/>EmDash core]
B --> C[Astro 6.0<br/>Theme engine]
B --> D[D1<br/>SQLite-compatible DB]
B --> E[R2<br/>Media storage]
B -->|capability binding| F[Dynamic Worker<br/>Plugin A]
B -->|capability binding| G[Dynamic Worker<br/>Plugin B]
F -.->|Only allowed actions| D
G -.->|Only allowed actions| E
| Aspect | WordPress | EmDash |
|---|---|---|
| Runtime | Origin server | Edge (300+ locations worldwide) |
| Scaling up | Add servers and load balancers | Automatic via Workers |
| Scaling down | Servers keep running | Zero traffic, zero cost |
| Caching | Built with plugins + CDN | Edge cache is standard |
| DB access | TCP to MySQL from the origin | Local access to D1 from the edge |
| Cold start | PHP process startup (hundreds of ms) | V8 isolate startup (milliseconds) |
WordPress often falls over when traffic spikes. 503s during a viral event are normal, and fixing them usually requires an infrastructure engineer. EmDash should be structurally more resilient as long as it stays on Cloudflare’s platform.
That said, WordPress performance can already be good enough for many sites if you use the right plugins. WP Rocket and Cloudflare APO can get you close to static-site speeds. Whether this is enough motivation to switch depends on the site.
Default Authentication Is Much Stronger
| Aspect | WordPress | EmDash |
|---|---|---|
| Default auth | Password | Passkey (passwordless) |
| 2FA | Added via plugin | Not needed; the passkey already covers MFA |
| SSO integration | Via plugins (SAML/OIDC/LDAP) | Via plugins, with automatic IdP metadata provisioning |
| Password DB | Exists (bcrypt hashes) | Does not exist |
EmDash does not store passwords at all. If there is no password database, password stuffing and brute-force attacks do not apply. WordPress defaults to password auth, and 2FA is up to the site owner. Both systems have the same four roles: administrator, editor, author, and contributor.
WordPress authentication plugins are mature, though. miniOrange, WP SAML Auth, and similar tools can build enterprise-grade SSO setups with Active Directory or LDAP integration.
How It Works Without a Password DB
To be precise, EmDash is not storing nothing at all. Passkeys (FIDO2 / WebAuthn) use public-key cryptography, so the server stores a public key instead of a password hash.
The registration flow looks like this:
- The server generates a random challenge and sends it to the browser
- The browser asks the authenticator to generate a key pair
- The user confirms with biometrics or a PIN
- The authenticator generates a secret/public key pair and keeps the secret key on the device
- The browser sends the public key and credential ID back to the server, which stores only those values
At login, the server sends a challenge, the device signs it with the secret key, and the server verifies the signature with the stored public key. No password ever travels across the wire.
sequenceDiagram
participant U as User
participant B as Browser
participant A as Authenticator<br/>(security chip)
participant S as EmDash server
Note over U,S: Registration flow
B->>S: Registration request
S->>B: Challenge + server data
B->>A: Request key-pair generation
U->>A: Biometric or PIN
A->>A: Generate secret/public key pair
A->>B: Public key + credential ID + signature
B->>S: Public key + credential ID + signature
S->>S: Save public key (no password stored)
Note over U,S: Login flow
B->>S: Login request
S->>B: Challenge + credential ID
B->>A: Request signature
U->>A: Biometric or PIN
A->>A: Sign the challenge with the secret key
A->>B: Signature data
B->>S: Signature data
S->>S: Verify signature with the stored public key
The important point is that leaking the public key is harmless. You cannot derive the secret key from it. That is a very different risk profile from a leaked password database.
| If leaked | Password DB | Passkey public-key DB |
|---|---|---|
| Offline brute-force | Possible; weak passwords fall quickly | Not possible; public key does not reveal the secret |
| Credential stuffing | Possible if passwords are reused | Not possible; each key pair is unique per site |
| Phishing | Works if the user enters the password on a fake site | Does not work; the authenticator checks the origin and will not sign for a fake site |
| Response after DB leak | Force every user to reset passwords | No action needed; the public key alone is useless |
Passkeys count as MFA because they combine device possession with biometrics or a PIN. One step gives you two factors, so there is no need to bolt on a separate 2FA plugin like you do in WordPress.
Content Monetization
EmDash supports x402, a proposed “internet-native payment standard,” out of the box. Set a price and wallet address on the content and you can charge per article with very little engineering work, at least according to Cloudflare.
Doing the same thing in WordPress usually means combining WooCommerce and MemberPress. You have to set up the payment provider contract, Stripe, webhooks, and a membership plugin, and getting it all working can take days or weeks. Plugin compatibility issues are common too.
WordPress does have a much richer e-commerce ecosystem, though. Monthly subscriptions, usage-based billing, coupons, affiliate programs, and integration with physical products are all well covered. x402 is good for per-article charging, but it may not handle more complex sales flows.
AI Agent Integration
Every EmDash instance includes a Model Context Protocol (MCP) server. Through the EmDash CLI, you can upload media, search content, and manage schemas programmatically, so the whole system is designed with AI agents in mind.
There are also Agent Skills for plugin creation and theme migration. For example, the “Block Kit Agent Skill” can convert WordPress blocks into EmDash format.
WordPress has a REST API too, but it was added later and often comes with authentication setup pain and plugin conflicts. A built-in MCP server is a clear advantage if you care about AI-agent compatibility in 2026.
Theme Development: PHP vs Astro
An EmDash theme is itself an Astro project: Pages, Layouts, Components, Styles, and Seed files that define content types and fields. Themes do not get database privileges either. They fetch content through EmDash’s API and never need raw SQL. By removing direct DB access from both plugins and themes, EmDash structurally eliminates the SQL-injection attack surface.
WordPress themes are PHP files, which means a theme can call $wpdb->query() or make external requests with file_get_contents(). Malicious themes have been discovered in the WordPress.org theme directory more than once. EmDash simply does not have this attack path.
| Aspect | WordPress theme | EmDash theme |
|---|---|---|
| Language | PHP (template tags) | Astro + TypeScript |
| Customization | Theme customizer (GUI) | Code editing (CLI / editor) |
| Theme store | 12,000+ (free and paid) | A few official themes so far |
| DB operations | Possible, including raw SQL | Not possible; API only |
| Security risk | Malware can arrive through themes | No direct attack surface |
| Learning curve | Basic PHP is enough | You need front-end development knowledge |
| No-code support | Theme customizer, Gutenberg | None |
For developers, Astro + TypeScript is modern and pleasant. For non-engineers, WordPress’s theme customizer and Gutenberg are much more approachable. That difference is about user audience, not technical merit.
Where WordPress Clearly Wins
Ecosystem Depth
With more than 59,000 plugins and 12,000 themes, there is usually already a plugin for whatever you want to do. WooCommerce for e-commerce, Yoast SEO for search, Contact Form 7 for forms, UpdraftPlus for backups. Each plugin has its own developer community, documentation, and tutorials.
EmDash’s ecosystem is starting from zero. SEO plugins, form builders, backup tools, and payment integrations are still missing or need to be built manually.
Non-Engineer Usability
Over 20 years, WordPress has become a CMS that non-engineers can actually operate. The admin screen works entirely in the browser, and posts, images, theme changes, and plugin installs are all GUI-driven. Gutenberg’s block-based editing is close to a Notion-like experience.
EmDash’s admin UI is still minimal and clearly aimed at engineers. Theme customization requires code, and plugin development assumes TypeScript knowledge. For someone who just wants to write blog posts, EmDash is still too technical.
Hosting Flexibility
WordPress runs everywhere, from cheap shared hosting to enterprise setups on AWS. In Japan, providers like Sakura Internet, Xserver, and Lolipop all support one-click WordPress installs. You can host it yourself or move it to the cloud, and migration procedures are well understood.
EmDash is really optimized for Cloudflare Workers. It is said to run elsewhere with workerd, the open-source Workers runtime, but real self-hosting examples are rare. In practice, that means you are much more dependent on Cloudflare’s service and pricing than you are with WordPress.
Information and Community
If you get stuck with WordPress, a search usually finds a Japanese solution right away. There is Stack Overflow, Qiita, Zenn, and countless blogs. There are also lots of Japanese books. Hiring WordPress developers is easy because PHP and WordPress experience is common worldwide.
With EmDash, you mostly have the official docs and GitHub issues. Japanese information is effectively nonexistent. Hiring is also hard because “EmDash experience” does not really exist yet.
Existing Assets and Workflows
There are already hundreds of millions of WordPress sites, each with their own custom themes, plugin settings, and operational workflows. Even if migration tools exist, the workflow rewrite cost can be bigger than the technical migration cost.
WooCommerce shops, bbPress forums, and LearnDash course sites are especially hard to move because so much depends on plugins. EmDash will need years to match that breadth.
Migration From WordPress
EmDash offers two migration paths: export a WXR file from WordPress and import it, or install the EmDash Exporter plugin and migrate through a secure endpoint. The latter is protected by WordPress application passwords and can also move media files automatically. Cloudflare claims the migration takes only a few minutes.
Custom post types become EmDash Collections. For WordPress theme migration, there is an Agent Skill called wordpress-theme-to-emdash.
Content migration is relatively easy; reproducing the look and feel of the theme and replacing plugin functionality is the real bottleneck. A simple blog might move in minutes, but a site with 10 or more plugins could take weeks.
What the v0.1.0 Beta Includes
The current release is a v0.1.0 preview beta. You can set it up instantly with npm create emdash@latest, and there is a one-click deploy button for Cloudflare. If you just want to try the admin screen, there is a Playground at emdashcms.com. The GitHub repo is emdash-cms/emdash, and the project is MIT licensed.
Cloudflare has been shipping platform pieces for Workers very quickly over the last few months: VoidZero’s Vite-native deploy platform, Vinext’s reimplementation of Next.js, and a real-time analytics stack on Workers. EmDash is part of that same wave.
I also covered the threat of third-party scripts in Cloudflare’s Client-Side Security GNN+LLM detection. EmDash tries to solve the problem at the root by making plugins incapable of doing evil in the first place.
Multilingual Support
Modern websites need multilingual support more often than before. Cross-border e-commerce, global corporate sites, and even personal blogs now often ship with English versions. WordPress and EmDash take very different approaches.
WordPress Multilingual Support
WordPress itself has no multilingual feature. You need plugins like WPML, Polylang, or TranslatePress.
| Plugin | Approach | Price | Notes |
|---|---|---|---|
| WPML | Duplicate posts by language | Paid ($39+/year) | The most common choice; strong WooCommerce integration |
| Polylang | Duplicate posts by language | Free version available | Lighter than WPML; easy to start with |
| TranslatePress | Edit translations from the front end | Free version available | Lets you see the page while translating |
| MultilingualPress | Split each language into a separate multisite | Paid | Enterprise-oriented; strong site isolation |
WPML and Polylang duplicate the post per language, so the Japanese and English versions are stored as separate posts. That doubles or triples the post count, and the setup gets messy fast: language switchers, hreflang output, and URL structure all have to be configured carefully.
Multilingual plugins also tend to create compatibility issues with other plugins. A cache plugin may fail to cache language-specific pages, an SEO plugin may output the wrong hreflang tags, and e-commerce plugins may lose fields during translation. The combinations explode, and troubleshooting takes time.
That said, these plugins are mature. They provide translation memory, translator role management, translation progress tracking, and integrations with external translation services like DeepL and Google Translate. Large multilingual workflows already know how to use them.
EmDash Multilingual Support
EmDash is built on Astro 6.0’s built-in i18n routing. Astro supports language-based routing at the framework level, so multilingual support is not bolted on later.
// astro.config.ts (EmDash theme-side configuration)
export default defineConfig({
i18n: {
defaultLocale: "ja",
locales: ["ja", "en", "zh-hans", "ko"],
routing: {
prefixDefaultLocale: false
// ja: /articles/slug
// en: /en/articles/slug
}
}
});
The edge location matters because Cloudflare Workers can handle locale detection and content routing before the request ever reaches an origin.
graph TD
A[Browser] -->|Request| B[Cloudflare Workers<br/>Edge location]
B -->|Accept-Language<br/>CF-IPCountry| C{Detect locale}
C -->|ja| D[Japanese content]
C -->|en| E[English content]
C -->|zh-hans| F[Chinese content]
D --> G[Fetch from D1<br/>edge cache]
E --> G
F --> G
WordPress multilingual plugins do locale detection on the origin server and fetch the relevant language from MySQL. EmDash does it at the edge, so the language-detection-to-redirect-to-content chain is structurally lower latency.
In the D1 content schema, translations are managed as fields on a Collection. Unlike WordPress, which duplicates the post by language, EmDash keeps it as one content entry with multiple language fields.
| Aspect | WordPress | EmDash |
|---|---|---|
| Multilingual implementation | Plugin (added later) | Built into the framework |
| Content structure | One post per language | One entry with multiple language fields |
| URL structure | Depends on plugin settings | Astro i18n routing |
| Locale detection | On the origin server | At the edge |
| hreflang tags | Output by the plugin | Generated by the framework |
| Translation management | Translation memory, progress tracking, translator roles | Basic field management |
| Machine translation integration | DeepL, Google Translate plugins | Possible via API, but no official integration yet |
| RTL support | Possible via plugins | Supported via Astro’s dir attribute |
| Maturity | Millions of sites already use it | Beta stage |
The architectural advantage is clear, but WordPress is still far ahead in translation workflows. Translation memory, translator roles, progress tracking, agency collaboration - those are still missing in EmDash.
For a personal blog or a small site, EmDash’s built-in approach is simpler. For a 50-language enterprise site or a large translation team, WordPress still has the workflow support you need.
URL Structure and Routing
If you use a CMS in production, URL structure and redirects are never optional. SEO often wants categories in the URL, redirects need fine control, and subdirectory installs need careful handling. WordPress has always been strong here because you can freely tweak it in functions.php.
WordPress URL Control
You can change permalinks through the admin UI, but serious customization usually means working with the Rewrite API in functions.php.
// functions.php: make a custom post type use /news/slug/
function custom_news_rewrite() {
add_rewrite_rule(
'^news/([^/]+)/?$',
'index.php?post_type=news&name=$matches[1]',
'top'
);
}
add_action('init', 'custom_news_rewrite');
// Change the permalink structure to /%category%/%postname%/
function custom_permalink_structure() {
global $wp_rewrite;
$wp_rewrite->set_permalink_structure('/%category%/%postname%/');
}
You can add redirect rules in .htaccess (Apache) or nginx.conf, register custom query variables with add_rewrite_tag, and conditionally redirect from template_redirect. In other words, PHP can do almost anything. And because 20 years of Stack Overflow answers exist, you can usually find the code snippet you need.
EmDash URL Control
EmDash is Astro 6.0-based, so routing follows Astro’s conventions. Astro uses file-based routing, where the structure under src/pages/ becomes the URL. It is written in TypeScript.
src/pages/
├── index.astro → /
├── about.astro → /about
├── articles/
│ └── [slug].astro → /articles/any-slug
└── [lang]/
└── articles/
└── [slug].astro → /en/articles/any-slug
Dynamic routes are handled with [slug].astro or [...path].astro, and getStaticPaths() controls what gets generated. Category-based URLs are easy to express.
// src/pages/[category]/[slug].astro
export async function getStaticPaths() {
const posts = await getCollection("posts");
return posts.map((post) => ({
params: {
category: post.data.category,
slug: post.slug,
},
props: { post },
}));
}
// → /tech/my-article, /diary/my-diary, etc.
Redirects are declared in astro.config.ts.
// astro.config.ts
export default defineConfig({
redirects: {
"/old-path": "/new-path",
"/blog/[...slug]": "/articles/[...slug]",
},
});
Astro file-based routing plus astro.config.ts plus middleware gives you the same kind of flexibility as WordPress’s functions.php + Rewrite API. Middleware lets you write pre-processing steps like auth checks, redirects, and header manipulation in TypeScript.
// src/middleware.ts
import { defineMiddleware } from "astro:middleware";
export const onRequest = defineMiddleware(async (context, next) => {
const url = new URL(context.request.url);
// Redirect /old-blog/* to /articles/*
if (url.pathname.startsWith("/old-blog/")) {
const newPath = url.pathname.replace("/old-blog/", "/articles/");
return context.redirect(newPath, 301);
}
return next();
});
URL Control Comparison
| Aspect | WordPress | EmDash (Astro) |
|---|---|---|
| Permalink setup | GUI + functions.php | astro.config.ts + file structure |
| Dynamic routing | Rewrite API (regex) | [slug].astro (file-based) |
| Redirects | .htaccess / functions.php | astro.config.ts / middleware |
| Middleware | Hook system (actions / filters) | src/middleware.ts (TypeScript) |
| Subdirectory deployment | site_url / home_url | base option |
| Custom query vars | add_rewrite_tag | URL params / Astro.url.searchParams |
| Language | PHP | TypeScript |
| Available knowledge | Huge (20 years of examples) | Mostly Astro docs |
The answer to “Can you write routing in TypeScript?” is yes. Astro’s file-based routing is more intuitive than WordPress’s Rewrite API and much less likely to turn into regex hell. The middleware model is also easier to follow than functions.php hooks.
That said, how freely EmDash can route inside Cloudflare Workers is a separate question. Astro alone can do almost anything, but EmDash prioritizes plugin and theme sandboxing. Some routing constraints may still exist on the theme side, and the beta docs are still thin.
WordPress’s Rewrite API is powerful, but internally every rule gets stored in wp_options as rewrite_rules, and matching happens on every request. That can hurt performance as the rule set grows. EmDash’s file-based routing is resolved at build time, so there is no runtime overhead.
WordPress’s 24 Years
I mentioned “24 years” at the top, but it is worth looking at what that actually means.
In 2003, 19-year-old Matt Mullenweg and Mike Little forked b2/cafelog, a PHP blogging tool, and turned it into WordPress. It started as a small blogging tool.
| Year | Version | Event |
|---|---|---|
| 2003 | 0.70 | Forked from b2/cafelog and was born |
| 2004 | 1.2 | Plugin API introduced. The ecosystem begins |
| 2005 | 1.5 | Theme system introduced. Automattic founded the same year |
| 2005 | 2.0 | WYSIWYG editor added |
| 2008 | 2.5 | Major admin redesign |
| 2010 | 3.0 | Custom post types added. A turning point from “blog” to “CMS” |
| 2011 | — | WooCommerce appears and WordPress becomes an e-commerce platform too |
| 2015 | 4.4 | REST API integrated into core |
| 2018 | 5.0 | Gutenberg block editor lands, splitting the community |
| 2024 | 6.x | Mullenweg vs WP Engine dispute. Governance issues surface |
| 2026 | 6.8+ | More than 40% of the web, with more than 10,000 vulnerability reports a year |
The 2010 WordPress 3.0 release was the real turning point. Custom post types made WordPress useful for more than blogs: e-commerce, corporate sites, portfolios, and real-estate sites. The next year WooCommerce arrived, and WordPress became a serious commerce platform.
The 2018 Gutenberg rollout was the most controversial change. The forced move from the classic editor to block-based editing drew a huge backlash, and the Classic Editor plugin surpassed 5 million installs. It is still used today.
In 2024, WordPress founder Mullenweg publicly criticized WP Engine and temporarily cut off access to WP Engine-related plugins from WordPress.org. That turned into a broader community debate about open-source governance versus commercial use.
The 24-year ecosystem is also carrying technical debt. The PHP process model creates structural security problems, exactly as described above. But on top of that debt sit 59,000 plugins, 12,000 themes, millions of developers, and countless businesses. What EmDash is trying to challenge is not just a product, but all of that accumulated weight.
Because this blog itself is built with Astro, I was curious the moment I saw that EmDash is built on Astro 6.0. The plugin sandbox design is coherent and offers a convincing answer to a problem WordPress has carried for 20 years. Whether v0.1.0 is actually ready for real use is another question, but I do want to try it.