We build and deploy EmDash CMS sites.
EmDash is an open-source CMS that runs inside the Astro application, with the admin and the site in one deployment. Stable 1.0 shipped on 28 September 2026. We build new EmDash sites and take them to production on Cloudflare or Node.
EmDash keeps the CMS inside your Astro application. Editors shape the content model in the admin, and developers get typed content.
-
Runs inside Astro
EmDash is an Astro integration, so the admin panel and the site deploy as one application. Pages query live content through Astro Live Collections in the same runtime. Integrations use the REST API or the CLI.
-
Collections built in the admin
Anyone with the Admin role adds collections and fields in the admin. Developers generate TypeScript types from that live model and export it as a seed file for a new database.
-
Drafts, preview and scheduling
An entry is a draft, scheduled or published. Editors share signed preview links that expire, and they can restore an earlier revision from the entry's history.
-
Translations on their own schedule
Each translation is a separate entry with its own slug, status and revisions. One locale can go live while another stays in draft.
-
A built-in MCP server
AI agents read and edit content through the MCP server in core. They sign in with OAuth 2.1 or a personal access token, and scopes and role checks limit what each one can change.
-
Plugins with declared capabilities
A plugin declares the access it needs. In sandboxed mode EmDash isolates its storage, limits the hosts it can call and asks for consent again when an update wants more.
-
Cloudflare or Node hosting
EmDash deploys to Cloudflare Workers with D1 and R2, or to a Node.js server with a SQL database and S3-compatible media. Both run in your own account or on your own server.
-
A WordPress importer
The importer in the admin analyses a WordPress site, sets up collections, imports content, copies the media and rewrites media URLs in the content.
Our EmDash CMS review records two local runs, on 0.42.0 and on stable 1.0.1. The 1.0.1 run repeated drafts, preview, publishing and revision restore, then restored a database and media backup into a fresh site and imported a synthetic WordPress site. Each ran locally on Node and SQLite, with no client deployment involved.
EmDash runs only inside Astro. wayf.ai is built with Astro, and we maintain the open-source Payload Astro Starter, which runs Payload behind an Astro front end. Our Astro CMS guide compares Payload, Storyblok, Sanity and Contentful for Astro sites.
We built a demo site on EmDash 1.1.0.
A business website on EmDash
We built this demo to show how we would build and deploy your business website on EmDash instead of WordPress. Every page, label and piece of text is editable in the CMS. The heat pump installer it advertises is made up.
Bielak & Sowa, a fictional installer from Poznań, with the site in Polish and English. - 90+
- Lighthouse mobile performance
- 100
- Lighthouse SEO
EmDash suits an Astro site run by one editorial team. Payload handles approvals and brand permissions better.
EmDash fits when
- The site is a new Astro build with one editorial team.
- Someone with the Admin role should be able to add collections and fields in the admin.
- You want the CMS and the site in one deployment, on Cloudflare or Node.
- Each translation should publish on its own schedule.
- Agents will read and edit content through the built-in MCP server.
Payload fits better when
- Content has to pass a review step before it goes live.
- Editors may change only their own brand or region.
- Staff need native SAML integration rather than sign-in through Cloudflare Access.
- Procurement asks for an SLA, a compliance certification or contractual support.
- Every schema change has to go through code review.
We are an official Payload partner, so weigh our Payload view with that in mind.
Send us the content types, the roles and the hosting you have in mind. We will tell you which platform suits the build.
Talk through the fitAn evaluation tests EmDash on your content before we scope the build. It ends in a written recommendation and an implementation scope.
What we need from you
- A representative sample of your content as it exists today, with its media.
- The editorial tasks your team handles every week, and time with the editors who carry them out.
- Who may publish, and what has to happen before an entry goes live.
- The hosting and the sign-in method you intend to use.
- The plugins and integrations the current site depends on.
- For a WordPress site, its export and the list of public URLs.
What you get back
- A prototype holding that content, pinned to an exact EmDash version and template commit.
- The evaluation sheet filled in, each check scored pass, partial or not demonstrated, with the custom work it needed.
- A database and media restore into a fresh environment, with a record of what came back.
- For a WordPress move, the import compared with the source and every old URL requested, with the redirects it needs.
- A written recommendation for EmDash, Payload or another platform on your shortlist, with the implementation scope for the build.
What the WordPress check found on our test site
EmDash 1.0.1 imported a synthetic WordPress site on 1 October 2026: six posts, two pages and four image attachments. The content and media came across, and the gaps in the table were left to us. On 1.2.0, on 7 October, the scheduled post kept its date and one pattern rule covered both forms of a permalink; redirects and internal links were still ours to add. On a client site, each finding of this kind goes into the recommendation with the work it takes.
Our local runs left scheduling, roles below Admin, translations, plugins, MCP, passkeys, SSO, Cloudflare deployment and production performance untested. An evaluation tests the ones your site depends on in your own setup, using the editable evaluation sheet. The full import run and its fixture are in the review.
| Check | EmDash 1.0.1 |
|---|---|
| Posts, pages and media against the export | Matched; the duplicate image file stored once |
| Scheduled post | Imported as a draft, without its date |
| Nested category | Imported without its parent |
| Internal links pointing at the new routes | 0 of 3 |
| Old public URLs reaching their content | 5 of 11; all 11 after five redirect rules |
We take an EmDash site from content model to production. Sign-in, backups and the upgrade path are in place before launch.
Content model and roles
We work out the collections and fields with your editors and generate the TypeScript types the templates use. Each person gets one of EmDash's five roles, and changes to the model stay with the Admin role. The model goes into a seed file, so staging and production start from the same structure.
Templates and preview
We build the Astro templates against live content and wire preview into them, so an editor sees a draft on the real page before publishing it. In our 0.42.0, 1.0.1 and 1.2.0 checks, EmDash and its Starter template served previews without a noindex directive, so we add one. From 1.2.0 a preview link also shows the draft on list pages. We set how long a preview link lasts to match how your team shares drafts.
In the 1.0.1 run, a new meta description on a published post reached the public page on save, without Publish changes. If your team reviews SEO changes before release, we test that step with your editors.
Sign-in
On Cloudflare we map Cloudflare Access to your identity provider's groups, and it becomes the only way into the admin. Other sites use passkeys, which EmDash sets up by default, or GitHub, Google or Microsoft Entra ID sign-in. Entra ID arrived in EmDash 1.1.0.
A passkey works only at the address where it was created. When a site moves from a staging domain to its own, a signed-in administrator can use EmDash's 1.2.0 handover link to continue at the new address and add a passkey. The separate Email users action can notify the other users, who then sign in by email and add a passkey.
Invitations and account recovery go out by email, so we connect an email provider before launch. Without one, a sole admin who loses access has to reset it through the database.
Hosting and backups
We deploy to your Cloudflare account or your own Node server. Scheduled publishing needs a Cron Trigger on Workers and a process that stays up on Node, and we set up whichever one applies.
EmDash does not restore its own JSON backups. Our backup routine copies the raw database, the media and the encryption keys, and before launch we restore them into a fresh environment and check the public site.
In the 1.0.1 run, on Node and SQLite, that restore brought
back content, media, revision history and the admin
account. The Starter
template still leaves SQLite's -wal and
-shm files out of .gitignore, and
they can hold content and email addresses, so we add them
before the first commit.
Moving from WordPress
We run EmDash's importer for posts, pages and media while the WordPress site is still reachable at its public address, which the media step needs. Then we request every old URL on the new site. In our 1.0.1 test, and again on 1.2.0, the importer created no redirects and left internal links on the old addresses, so we add the redirects and rewrite the links.
Content lands in the default locale, and visibility rules drop. Scheduled dates dropped before 1.2.0; on 1.2.0 a future-dated post kept its schedule. In both tests a nested category lost its parent. From 1.2.0 a Classic-editor table with only text in its cells arrives as a table, and one with merged cells still arrives as plain text. We restore what is lost and relink the translations WPML or Polylang had grouped.
Memberships, forms, advertising and anything else a WordPress plugin handled get rebuilt as an EmDash plugin or moved to a separate service. The old site stays up until each one works on the new site.
- Cloudflare Workers
- D1
- R2
- Node.js
- SQLite
- libSQL
- PostgreSQL
- S3-compatible storage
Questions we get asked about EmDash CMS.
-
Is EmDash ready for a production site?
Yes. EmDash released stable 1.0 on 28 September 2026, and we deploy it to production. An existing 0.x site follows the 1.0 upgrade guide. A 1.x site updates with the
upgrade-emdashcommand, which installs the packages and writes a work order but applies no database migration and deploys nothing. Core migrations only run forward, so we rehearse every upgrade on a copy of the site before it reaches production. -
Can EmDash hold content for approval before it goes live?
Not in core. An EmDash entry is draft, scheduled or published, with no review state. A plugin can block publication through the
content-policyhook, which is custom work to specify, build and maintain. When approval is a hard requirement we build on Payload, which has drafts, versions and scheduled publishing in core and sells approval workflows as an enterprise feature. -
Can we move a WordPress site to EmDash?
Yes, and we run the migration. EmDash's importer moves posts, pages and media. In our 1.0.1 test, and again on 1.2.0, it created no redirects and left internal links on their old addresses, so we add the redirects and rewrite the links. Visibility rules and WPML or Polylang translation groups do not carry over either, and we set those up again after the import. From 1.2.0, a post scheduled for a future date keeps its schedule. Anything a WordPress plugin did, such as memberships or forms, gets rebuilt as an EmDash plugin or moved to a separate service.
-
We run Strapi today. Is EmDash an option?
For a new site built on Astro, yes. EmDash runs only inside an Astro application. When an existing Strapi build needs a successor, we move it to Payload. Our Strapi page covers maintenance and migration.
-
How does an EmDash engagement start?
With a consultation that costs nothing. When the platform choice is still open, an evaluation puts your content through EmDash and ends in a written recommendation. After that we write the scope and agree a fixed price against it before the build starts.
Tell us about the EmDash site you want to build.
Send us the content types, who publishes and where the site should run. We will scope the build and come back with a fixed price.