EmDash CMS vs Craft CMS: Which One Should You Choose?

EmDash CMS vs Craft CMS: Which One Should You Choose?

Craft CMS has built a loyal following among agencies for a specific reason: it's genuinely flexible without WordPress's plugin sprawl, and it sells licenses instead of subscriptions. EmDash is open-source and free at the core, with a different content model and a different security philosophy. This guide compares both for teams — especially agencies — deciding between a licensed PHP platform and an open-source, self-hosted one.

Table of Contents
  1. Quick Answer
  2. Pricing: Perpetual License vs. Free and Open Source
  3. Technology Stack: PHP/Twig vs. Astro/TypeScript
  4. Content Modeling Flexibility
  5. Who Actually Chooses Craft
  6. Plugin and Extension Security
  7. Where Craft CMS Pulls Ahead
  8. Where EmDash Pulls Ahead
  9. Frequently Asked Questions
  10. Is Craft CMS's licensing better for agencies than EmDash's open-source model?
  11. Do I have to pay Craft's $99/year renewal fee?
  12. Is PHP or TypeScript better for a new project in 2026?
  13. Does EmDash have anything like Craft's Plugin Store?
  14. The Bottom Line
  15. Sources

Quick Answer

Craft CMS is the stronger choice if you want a mature, agency-proven PHP platform with a one-time license fee instead of a subscription, and your team is comfortable with PHP/Twig. EmDash is the stronger choice if you want a fully open-source platform with no license cost at all, sandboxed plugin security, and a modern Astro/TypeScript stack instead of PHP.

Pricing: Perpetual License vs. Free and Open Source

When you pay for a commercial Craft or plugin edition, legally speaking, you own a perpetual license to use that edition at the installed version. Once you purchase the license, you are entitled to use the licensed version indefinitely, without paying any additional license fees.

Craft's 2026 pricing is genuinely straightforward: Solo is free forever for one user; Team is $279 per project ($99/year for updates after year one); Pro is $399 per project (unlimited users, same renewal terms); Enterprise is custom. That's a one-time cost per project rather than an ongoing subscription — genuinely attractive for an agency building many client sites, since each is a single, predictable license fee rather than a recurring per-project SaaS bill. EmDash has no license cost at all in any tier — it's fully open-source — but also doesn't offer the "buy once, skip updates forever if you want" model Craft's perpetual license provides; EmDash's ongoing cost is purely your own infrastructure.

Read also:

Technology Stack: PHP/Twig vs. Astro/TypeScript

Craft runs on a single-language PHP/Twig stack, which reviewers note reduces long-term maintenance overhead compared to WordPress's increasingly fragmented PHP-plus-React architecture — a real advantage for teams that want one coherent language across templates and backend. EmDash is TypeScript throughout, front end (Astro) and backend alike. Neither stack is objectively better; it depends entirely on what your team already knows well. An agency with deep PHP expertise will find Craft's stack more immediately productive; a team already in the TypeScript/JavaScript ecosystem will find EmDash's more natural.

Content Modeling Flexibility

Craft's flexible content modeling is one of its most consistently praised features — it handles everything from simple blogs to complex ecommerce catalogs, and even the free Solo edition includes full content modeling, multi-site support, and GraphQL with zero licensing cost. EmDash's structured content model — typed, dedicated tables per content type — covers similar ground conceptually, with content defined through the CMS's own schema system rather than Craft's field-and-block modeling approach specifically.

Who Actually Chooses Craft

Craft CMS is best suited for agencies, small to medium-sized businesses, and organizations looking for a high degree of customization and control over their website's content and structure. That agency fit is worth taking seriously — Craft has spent years specifically optimizing for the workflow of a dev shop building many distinct client sites, each needing its own license. EmDash doesn't have that same multi-client-license model; a self-hosted, open-source platform doesn't need one, since there's no license to buy per project in the first place.

Plugin and Extension Security

Craft's plugin ecosystem runs through its official Plugin Store, with commercial and free plugins reviewed before listing — a reasonable middle ground, though plugins still generally run with broad access once installed, similar to most PHP CMS platforms. EmDash's plugins run sandboxed with explicit, granted permissions rather than broad access by default, a stricter architectural approach to the same underlying concern.

Where Craft CMS Pulls Ahead

  • A one-time perpetual license instead of a recurring subscription — genuinely attractive for agencies managing many client projects.
  • A mature, single-language PHP/Twig stack with years of agency-workflow refinement.
  • A free Solo edition with full content modeling and GraphQL, zero cost for single-user projects.
  • A reviewed official Plugin Store with a longer track record than EmDash's newer ecosystem.

Where EmDash Pulls Ahead

  • Fully open-source and free at every tier — no license fee at any scale.
  • Sandboxed, permission-scoped plugin security rather than broad plugin access by default.
  • A modern TypeScript/Astro stack for teams already working in that ecosystem.
  • A built-in MCP server for AI-native, programmatic content management.

Frequently Asked Questions

Is Craft CMS's licensing better for agencies than EmDash's open-source model?

It can be, specifically for agencies managing many separate client projects — Craft's perpetual per-project license is a well-understood, predictable cost structure. EmDash has no license cost at all, which is simpler in a different way: there's nothing to buy per project, just infrastructure to run.

Do I have to pay Craft's $99/year renewal fee?

Only if you want ongoing updates. The license itself is perpetual for the version you purchased — you can keep running that version indefinitely without paying the renewal, though you'd stop receiving new updates and security patches for the CMS itself.

Is PHP or TypeScript better for a new project in 2026?

Neither is objectively better — it depends on your team's existing expertise. Craft's PHP/Twig stack has two decades of ecosystem maturity behind it; EmDash's TypeScript/Astro stack is more aligned with how most new JavaScript-first teams are building today.

Does EmDash have anything like Craft's Plugin Store?

EmDash has a plugin system, but a smaller catalog than Craft's more established Plugin Store, reflecting EmDash's shorter time in the market — offset by a stricter sandboxed security model applied to whatever plugins do exist.

The Bottom Line

If you're an agency that values a proven, one-time-license PHP platform with years of workflow refinement, Craft CMS remains one of the strongest options in that specific niche. If you want a fully open-source, modern TypeScript platform with sandboxed plugin security and no license fees at any scale, EmDash is the stronger fit. See how it compares to WordPress, the other major PHP-based CMS in this series, for a related comparison.

Sources

Share

Comments

Write a comment

Related Articles

Login Works in Production but Fails on localhost: The secure Cookie Flag Gotcha

July 16, 2026

Login Works in Production but Fails on localhost: The secure Cookie Flag Gotcha

Google Analytics (GA4) Not Tracking Anything and No Console Errors: Check Your CSP First

July 16, 2026

Google Analytics (GA4) Not Tracking Anything and No Console Errors: Check Your CSP First

Native Module Build Fails on Shared Hosting (node-gyp, Old glibc/Python): The .npmrc Fix

July 16, 2026

Native Module Build Fails on Shared Hosting (node-gyp, Old glibc/Python): The .npmrc Fix

Login Works in Production but Fails on localhost: The secure Cookie Flag Gotcha

Login Works in Production but Fails on localhost: The secure Cookie Flag Gotcha

TL;DR — A custom session-cookie login flow appeared to succeed on localhost (the OTP verified, the response looked fine) but every subsequent request to a login-gated page treated the visitor as logged out. Identical code worked fine on the live HTTPS site. The cookie's Secure attribute was hardcoded to true — and per the cookie spec, browsers never store or send a Secure cookie over a plain, non-HTTPS connection.

Table of Contents
  1. Diagnostic
  2. Root cause
  3. Fix
  4. Lessons learned

Diagnostic

Check the actual Set-Cookie response header and the browser's own cookie storage panel — on localhost over http://, the cookie is sent by the server but never actually stored by the browser.

Root cause

// before -- assumes the app is always served over HTTPS
setCookie("session", token, { secure: true, httpOnly: true });
emdashkits.com

A cookie config that quietly assumes "we're always on HTTPS" breaks the instant you test over plain HTTP, which local dev servers commonly are.

Read also:

Fix

// after -- derive secure from the actual request protocol
const isHttps = request.url.startsWith("https://");
setCookie("session", token, { secure: isHttps, httpOnly: true });
emdashkits.com

Lessons learned

  • Any Secure-flagged cookie needs to key off the real request scheme, not an assumption baked in once at cookie-creation time.
  • "Works in production, silently fails in local dev" is a strong signal to check cookie flags before anything else in an auth flow.
  • Check other cookies in the same codebase for the same hardcoded assumption — if one cookie has this bug, sibling cookies set the same way are worth auditing too.
Share
Previous Article

Google Analytics (GA4) Not Tracking Anything and No Console Errors: Check Your CSP First

Comments

Write a comment

Related Articles

Google Analytics (GA4) Not Tracking Anything and No Console Errors: Check Your CSP First

July 16, 2026

Google Analytics (GA4) Not Tracking Anything and No Console Errors: Check Your CSP First

Native Module Build Fails on Shared Hosting (node-gyp, Old glibc/Python): The .npmrc Fix

July 16, 2026

Native Module Build Fails on Shared Hosting (node-gyp, Old glibc/Python): The .npmrc Fix

Uploaded Images Disappear After Every Deploy on Shared Hosting (and Other Reverse-Proxy Gotchas)

July 16, 2026

Uploaded Images Disappear After Every Deploy on Shared Hosting (and Other Reverse-Proxy Gotchas)

Google Analytics (GA4) Not Tracking Anything and No Console Errors: Check Your CSP First

Google Analytics (GA4) Not Tracking Anything and No Console Errors: Check Your CSP First

TL;DR — GA4's gtag.js snippet was installed correctly, the page loaded with no visible JavaScript error, and GA4's real-time report still showed zero activity. The CMS's default Content-Security-Policy had no allowance for analytics domains and no config option to add one — so every request to Google's tracking endpoints was blocked at the browser level before it could fail loudly.

Table of Contents
  1. Diagnostic
  2. Root cause
  3. Lessons learned

Diagnostic

Check the browser's dedicated CSP violation reporting, not the regular console error list — CSP blocks are reported through their own channel, not thrown as normal script errors, so "no console errors" doesn't mean nothing was blocked.

Root cause

The CSP's script-src and connect-src directives had no entry for googletagmanager.com or google-analytics.com, and the CMS exposed no configuration surface to add one — the only way in was patching the CSP directives directly.

// patch-package: add analytics domains to the existing CSP directives
scriptSrc.push("https://www.googletagmanager.com");
connectSrc.push("https://www.google-analytics.com", "https://www.googletagmanager.com");
emdashkits.com
Read also:

Lessons learned

  • "No console errors" is not proof nothing was blocked — CSP violations live in their own reporting surface and are easy to miss if you're only scanning for red error text.
  • Before adding any third-party script tag to a site with a CSP already in place, check the CSP's directives first rather than assuming a silently-empty analytics dashboard means a snippet-installation mistake.
Share
Previous Article

Native Module Build Fails on Shared Hosting (node-gyp, Old glibc/Python): The .npmrc Fix

Next Article

Login Works in Production but Fails on localhost: The secure Cookie Flag Gotcha

Comments

Write a comment

Related Articles

Login Works in Production but Fails on localhost: The secure Cookie Flag Gotcha

July 16, 2026

Login Works in Production but Fails on localhost: The secure Cookie Flag Gotcha

Native Module Build Fails on Shared Hosting (node-gyp, Old glibc/Python): The .npmrc Fix

July 16, 2026

Native Module Build Fails on Shared Hosting (node-gyp, Old glibc/Python): The .npmrc Fix

Uploaded Images Disappear After Every Deploy on Shared Hosting (and Other Reverse-Proxy Gotchas)

July 16, 2026

Uploaded Images Disappear After Every Deploy on Shared Hosting (and Other Reverse-Proxy Gotchas)