← Back to Home

EmDash — The Astro-Native CMS That's the Spiritual Successor to WordPress (Self-Hosted Guide)

EmDash — The Modern Astro-Native CMS: Complete Self-Hosting Guide

What if WordPress were rebuilt from scratch with today's tools — Astro, TypeScript, sandboxed plugins, and structured content? That's exactly what EmDash is: a full-stack, Astro-native CMS that carries forward WordPress's best ideas (extensibility, admin UX, plugin ecosystem) on a modern, type-safe foundation.

Launched in April 2026 by a team of former WordPress contributors and Astro core members, EmDash has already gained 10,700+ GitHub stars. Its killer feature is sandboxed plugins — plugins run in isolated Worker environments, each with a declared capability manifest, solving the #1 security problem that has plagued WordPress for two decades.

In this guide, you'll learn what makes EmDash different, how to self-host it with Docker, and how to migrate your existing WordPress site.

Why EmDash Is Trending

EmDash exploded on GitHub because it addresses the pain points that have accumulated across two decades of WordPress dominance:

  • Security: 96% of WordPress vulnerabilities come from plugins. EmDash plugins run in sandboxed Worker isolates with explicit capability declarations — a plugin that requests read:content and email:send can do exactly that and nothing else.
  • Structured content: WordPress stores rich text as HTML with metadata embedded in comments. EmDash uses Portable Text — a structured JSON format that decouples content from presentation. Your content renders as a web page, mobile app, email, or API response without parsing HTML.
  • Type safety: Content types are defined in the database, not in code. EmDash auto-generates TypeScript types from your live schema. Full type safety and autocomplete from query to template.
  • Agent-ready: Built-in MCP server, CLI for programmatic management, and skill files for AI-assisted plugin development.
  • Portable: Runs on Cloudflare (D1 + R2 + Workers) or any Node.js server with SQLite. Same codebase, no lock-in.

Architecture Overview

EmDash Architecture

EmDash is structured as a layered system. At the top, the Astro application (your site) integrates EmDash as a plugin. Below it, the EmDash Core handles routing, authentication, and the admin panel. The Storage Layer abstracts the database (SQLite, D1, PostgreSQL) and file storage (local, S3, R2) behind portable interfaces. Plugins run in isolated sandboxes with capability manifests, communicating via lifecycle hooks. The MCP Server exposes content management to AI agents, and the CLI handles migrations, type generation, and content operations.

Key Components

  • EmDash Core (emdash/astro) — The Astro integration that adds the admin panel, REST API, auth, media library, and plugin system to any Astro project
  • Portable Text Engine — Structured content storage using the Portable Text JSON format, decoupling content from its HTML representation
  • Plugin Sandbox — Isolated Worker environments (Dynamic Worker Loaders on Cloudflare, in-process safe mode on Node.js) with capability-based security
  • Database Abstraction — Kysely-based SQL abstraction supporting SQLite, D1, Turso/libSQL, and PostgreSQL
  • Storage Abstraction — S3-compatible API supporting local filesystem, R2, and AWS S3
  • MCP Server — Built-in Model Context Protocol server for AI tool integration
  • Auth System — Passkey-first (WebAuthn) with OAuth and magic link fallbacks, RBAC with four roles
  • WordPress Migration Engine — Import from WXR exports, REST API, or WordPress.com

Prerequisites

Before you begin, make sure you have:

  • Node.js 20+ and npm / pnpm installed
  • Docker and Docker Compose (for the self-hosted setup)
  • A domain name (if deploying to production)
  • Basic familiarity with Astro and TypeScript

Installation and Setup

Quick Start with npm (No Docker)

The fastest way to try EmDash is with the Astro template:

# Create a new EmDash blog project
npm create astro@latest -- --template @emdash-cms/template-blog

cd my-emdash-blog
npm install
npm run dev

Open http://localhost:4321/_emdash/admin to access the admin panel. The first-run wizard will guide you through creating an admin account.

Local Development with SQLite (No Cloudflare Required)

EmDash works great with local SQLite for development. Make sure your astro.config.mjs is set up:

// astro.config.mjs
import emdash from "emdash/astro";
import { sqlite } from "emdash/db";

export default defineConfig({
  integrations: [emdash({ database: sqlite() })],
});

Generate TypeScript types from your content schema:

npx emdash types

Query content in your Astro components with full type safety:

---
import { getEmDashCollection } from "emdash";
const { entries: posts } = await getEmDashCollection("posts");
---

{posts.map((post) => <article>{post.data.title}</article>)}

Self-Hosted Docker Setup

For production, here's a complete Docker Compose setup with SQLite (no external database needed):

# docker-compose.yml
version: "3.8"

services:
  emdash:
    image: node:22-alpine
    container_name: emdash
    restart: unless-stopped
    working_dir: /app
    ports:
      - "4321:4321"
    volumes:
      - ./app:/app
      - emdash_data:/app/data
    environment:
      - NODE_ENV=production
      - EMDASH_SECRET=change-this-to-a-random-secret
      - EMDASH_DB_TYPE=sqlite
      - EMDASH_DB_PATH=/app/data/emdash.db
      - EMDASH_STORAGE_TYPE=local
      - EMDASH_STORAGE_PATH=/app/data/media
      - EMDASH_URL=https://yourdomain.com
    command: >
      sh -c "
      npm install &&
      npx emdash build &&
      npx emdash start
      "
    healthcheck:
      test: ["CMD", "wget", "--spider", "http://localhost:4321/_emdash/admin"]
      interval: 30s
      timeout: 10s
      retries: 3

volumes:
  emdash_data:

But the recommended approach is to build your Astro site and serve it with nginx:

# Dockerfile
FROM node:22-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npx emdash build

FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

Environment Variables

Variable Description Default
EMDASH_SECRET Secret key for encryption and sessions Required
EMDASH_DB_TYPE Database type: sqlite, d1, postgres sqlite
EMDASH_DB_PATH Path to SQLite database file ./data/emdash.db
EMDASH_STORAGE_TYPE Storage backend: local, r2, s3 local
EMDASH_URL Public URL of your EmDash site Required for production

WordPress Migration

One of EmDash's standout features is the WordPress import wizard. It supports three migration paths:

1. WXR Export Import

# Export from WordPress admin: Tools → Export → All content
# Then import into EmDash:
npx emdash import:wxr ./wordpress-export.xml

2. REST API Migration

npx emdash import:rest https://old-wordpress-site.com/wp-json

3. WordPress.com Import

npx emdash import:wpcom your-wordpress-com-site

The migration engine imports posts, pages, media, categories, tags, and navigation menus. EmDash also provides agent skill files that help port WordPress plugins to the EmDash plugin API.

Plugin Development

EmDash plugins use a clean definePlugin() API with capability manifests:

// my-plugin.ts
export default () =>
  definePlugin({
    id: "notify-on-publish",
    capabilities: ["read:content", "email:send"],
    hooks: {
      "content:afterSave": async (event, ctx) => {
        if (event.content.status !== "published") return;
        await ctx.email.send({
          to: "editors@example.com",
          subject: `New post: ${event.content.title}`,
        });
      },
    },
  });

Available hook points include:

  • content:beforeSave / content:afterSave — Content lifecycle
  • user:afterLogin / user:afterRegister — Authentication events
  • admin:beforeRender — Admin UI customization
  • api:beforeResponse — API middleware hooks

MCP Integration

EmDash ships with a built-in MCP server, enabling AI tools like Claude, ChatGPT, and Cursor to interact with your CMS directly:

# Start the MCP server
npx emdash mcp-server

This exposes content operations as MCP tools: listCollections, getPosts, createPost, updatePost, deletePost, searchContent, and manageMedia. AI agents can create and edit content programmatically.

Comparison: EmDash vs WordPress vs Astro Content Collections

  • Plugin security: EmDash — Sandboxed isolates. WordPress — Full access. Astro Content Collections — N/A.
  • Content format: EmDash — Portable Text (JSON). WordPress — HTML + comments. Astro Content Collections — Markdown/MDX.
  • Type safety: EmDash — Generated TypeScript. WordPress — None. Astro Content Collections — Manual types.
  • Database: EmDash — SQLite / D1 / PostgreSQL. WordPress — MySQL/MariaDB. Astro Content Collections — Filesystem.
  • Admin UI: EmDash — Built-in visual builder. WordPress — Built-in. Astro Content Collections — None.
  • MCP / Agent support: EmDash — Native. WordPress — Via plugins. Astro Content Collections — None.
  • Deployment: EmDash — Node.js / Cloudflare. WordPress — LAMP stack. Astro Content Collections — Static/SSR.
  • Plugin system: EmDash — definePlugin() API. WordPress — WP Plugin API. Astro Content Collections — N/A.

Verification Checklist

After setting up your EmDash instance, run through this checklist:

  • ✅ Admin panel accessible at /_emdash/admin (200)
  • ✅ Able to create a new content collection
  • ✅ Rich text editor loads and saves content correctly
  • ✅ Media upload works (drag-and-drop)
  • ✅ Public site renders content from the CMS
  • ✅ Type generation works: npx emdash types
  • ✅ MCP server starts and exposes tools
  • ✅ Passkey / OAuth login works
  • ✅ WordPress import completes without errors

Resources

← Retour à l'Accueil

EmDash — Le CMS Natif Astro, Successeur Spirituel de WordPress (Guide Auto-Hébergement)

EmDash — Le CMS Natif Astro Moderne : Guide Complet d'Auto-Hébergement

Et si WordPress était reconstruit de zéro avec les outils d'aujourd'hui — Astro, TypeScript, plugins sandboxés et contenu structuré ? C'est exactement ce qu'est EmDash : un CMS full-stack natif Astro qui reprend les meilleures idées de WordPress (extensibilité, interface d'administration, écosystème de plugins) sur des fondations modernes et type-safe.

Lancé en avril 2026 par une équipe d'anciens contributeurs WordPress et membres du noyau Astro, EmDash a déjà accumulé plus de 10 700 étoiles GitHub. Sa fonctionnalité phare est les plugins sandboxés — les plugins s'exécutent dans des environnements Worker isolés, chacun avec un manifeste de capacités déclarées, résolvant le problème de sécurité numéro 1 qui a tourmenté WordPress pendant deux décennies.

Dans ce guide, vous découvrirez ce qui rend EmDash unique, comment l'auto-héberger avec Docker, et comment migrer votre site WordPress existant.

Pourquoi EmDash est Tendance

EmDash a explosé sur GitHub parce qu'il répond aux points douloureux accumulés en deux décennies de domination WordPress :

  • Sécurité : 96% des vulnérabilités WordPress proviennent des plugins. Les plugins EmDash s'exécutent dans des environnements Worker sandboxés avec des déclarations de capacités explicites — un plugin qui demande read:content et email:send peut faire exactement cela et rien d'autre.
  • Contenu structuré : WordPress stocke le texte riche comme du HTML avec des métadonnées intégrées dans des commentaires. EmDash utilise Portable Text — un format JSON structuré qui dissocie le contenu de sa présentation. Votre contenu s'affiche comme page web, application mobile, email ou réponse API sans avoir à parser du HTML.
  • Type safety : Les types de contenu sont définis dans la base de données, pas dans le code. EmDash génère automatiquement des types TypeScript à partir de votre schéma en direct. Type safety complète et autocomplétion de la requête au template.
  • Prêt pour les agents IA : Serveur MCP intégré, CLI pour la gestion programmatique, et fichiers de compétences pour le développement de plugins assisté par IA.
  • Portable : Fonctionne sur Cloudflare (D1 + R2 + Workers) ou n'importe quel serveur Node.js avec SQLite. Même codebase, pas de verrouillage.

Architecture

Architecture EmDash

EmDash est structuré comme un système en couches. En haut, l'application Astro (votre site) intègre EmDash comme plugin. En dessous, le noyau EmDash gère le routage, l'authentification et le panneau d'administration. La couche de stockage abstrait la base de données (SQLite, D1, PostgreSQL) et le stockage de fichiers (local, S3, R2) derrière des interfaces portables. Les plugins s'exécutent dans des sandbox isolés avec des manifestes de capacités, communiquant via des hooks de cycle de vie. Le serveur MCP expose la gestion de contenu aux agents IA, et la CLI gère les migrations, la génération de types et les opérations de contenu.

Composants Clés

  • Noyau EmDash (emdash/astro) — L'intégration Astro qui ajoute le panneau d'administration, l'API REST, l'auth, la médiathèque et le système de plugins à tout projet Astro
  • Moteur Portable Text — Stockage de contenu structuré utilisant le format JSON Portable Text, dissociant le contenu de sa représentation HTML
  • Sandbox de Plugins — Environnements Worker isolés (Dynamic Worker Loaders sur Cloudflare, mode sécurisé in-process sur Node.js) avec sécurité basée sur les capacités
  • Abstraction Base de Données — Abstraction SQL basée sur Kysely supportant SQLite, D1, Turso/libSQL et PostgreSQL
  • Abstraction Stockage — API compatible S3 supportant le système de fichiers local, R2 et AWS S3
  • Serveur MCP — Serveur Model Context Protocol intégré pour l'intégration d'outils IA
  • Système d'Auth — Passkey-first (WebAuthn) avec OAuth et liens magiques, RBAC avec quatre rôles
  • Moteur de Migration WordPress — Import à partir d'exports WXR, API REST ou WordPress.com

Prérequis

Avant de commencer, assurez-vous d'avoir :

  • Node.js 20+ et npm / pnpm installés
  • Docker et Docker Compose (pour la configuration auto-hébergée)
  • Un nom de domaine (pour le déploiement en production)
  • Une familiarité de base avec Astro et TypeScript

Installation et Configuration

Démarrage Rapide avec npm (Sans Docker)

Le moyen le plus rapide d'essayer EmDash est avec le template Astro :

# Créer un nouveau projet blog EmDash
npm create astro@latest -- --template @emdash-cms/template-blog

cd mon-blog-emdash
npm install
npm run dev

Ouvrez http://localhost:4321/_emdash/admin pour accéder au panneau d'administration. L'assistant de premier démarrage vous guidera pour créer un compte administrateur.

Développement Local avec SQLite (Cloudflare Non Requis)

EmDash fonctionne très bien avec SQLite local pour le développement. Assurez-vous que votre astro.config.mjs est configuré :

// astro.config.mjs
import emdash from "emdash/astro";
import { sqlite } from "emdash/db";

export default defineConfig({
  integrations: [emdash({ database: sqlite() })],
});

Générez les types TypeScript à partir de votre schéma de contenu :

npx emdash types

Interrogez le contenu dans vos composants Astro avec une type safety complète :

---
import { getEmDashCollection } from "emdash";
const { entries: articles } = await getEmDashCollection("posts");
---

{articles.map((article) => <article>{article.data.title}</article>)}

Configuration Docker Auto-Hébergée

Pour la production, voici une configuration Docker Compose complète avec SQLite (pas besoin de base de données externe) :

# docker-compose.yml
version: "3.8"

services:
  emdash:
    image: node:22-alpine
    container_name: emdash
    restart: unless-stopped
    working_dir: /app
    ports:
      - "4321:4321"
    volumes:
      - ./app:/app
      - emdash_data:/app/data
    environment:
      - NODE_ENV=production
      - EMDASH_SECRET=change...et
      - EMDASH_DB_TYPE=sqlite
      - EMDASH_DB_PATH=/app/data/emdash.db
      - EMDASH_STORAGE_TYPE=local
      - EMDASH_STORAGE_PATH=/app/data/media
      - EMDASH_URL=https://votredomaine.com
    command: >
      sh -c "
      npm install &&
      npx emdash build &&
      npx emdash start
      "
    healthcheck:
      test: ["CMD", "wget", "--spider", "http://localhost:4321/_emdash/admin"]
      interval: 30s
      timeout: 10s
      retries: 3

volumes:
  emdash_data:

Mais l'approche recommandée est de construire votre site Astro et de le servir avec nginx :

# Dockerfile
FROM node:22-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npx emdash build

FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

Variables d'Environnement

Variable Description Défaut
EMDASH_SECRET Clé secrète pour le chiffrement et les sessions Requis
EMDASH_DB_TYPE Type de base de données : sqlite, d1, postgres sqlite
EMDASH_DB_PATH Chemin du fichier SQLite ./data/emdash.db
EMDASH_STORAGE_TYPE Backend de stockage : local, r2, s3 local
EMDASH_URL URL publique de votre site EmDash Requis en production

Migration depuis WordPress

L'une des fonctionnalités phares d'EmDash est l'assistant d'import WordPress. Il supporte trois méthodes de migration :

1. Import d'Export WXR

# Exporter depuis l'admin WordPress : Outils → Exporter → Tout le contenu
# Puis importer dans EmDash :
npx emdash import:wxr ./export-wordpress.xml

2. Migration via API REST

npx emdash import:rest https://ancien-site-wordpress.com/wp-json

3. Import WordPress.com

npx emdash import:wpcom votre-site-wordpress-com

Le moteur de migration importe les articles, pages, médias, catégories, tags et menus de navigation. EmDash fournit également des fichiers de compétences pour agents IA qui aident à porter les plugins WordPress vers l'API de plugins EmDash.

Développement de Plugins

Les plugins EmDash utilisent une API definePlugin() propre avec des manifests de capacités :

// mon-plugin.ts
export default () =>
  definePlugin({
    id: "notifier-sur-publication",
    capabilities: ["read:content", "email:send"],
    hooks: {
      "content:afterSave": async (event, ctx) => {
        if (event.content.status !== "published") return;
        await ctx.email.send({
          to: "editeurs@example.com",
          subject: `Nouvel article : ${event.content.title}`,
        });
      },
    },
  });

Les points d'accroche disponibles incluent :

  • content:beforeSave / content:afterSave — Cycle de vie du contenu
  • user:afterLogin / user:afterRegister — Événements d'authentification
  • admin:beforeRender — Personnalisation de l'interface admin
  • api:beforeResponse — Hooks middleware API

Intégration MCP

EmDash est livré avec un serveur MCP intégré, permettant aux outils IA comme Claude, ChatGPT et Cursor d'interagir directement avec votre CMS :

# Démarrer le serveur MCP
npx emdash mcp-server

Cela expose les opérations de contenu comme outils MCP : listCollections, getPosts, createPost, updatePost, deletePost, searchContent et manageMedia. Les agents IA peuvent créer et modifier du contenu par programmation.

Comparaison : EmDash vs WordPress vs Astro Content Collections

  • Sécurité des plugins : EmDash — Sandbox isolés. WordPress — Accès total. Astro Content Collections — N/A.
  • Format de contenu : EmDash — Portable Text (JSON). WordPress — HTML + commentaires. Astro Content Collections — Markdown/MDX.
  • Type safety : EmDash — TypeScript généré. WordPress — Aucun. Astro Content Collections — Types manuels.
  • Base de données : EmDash — SQLite / D1 / PostgreSQL. WordPress — MySQL/MariaDB. Astro Content Collections — Système de fichiers.
  • Interface admin : EmDash — Constructeur visuel intégré. WordPress — Intégré. Astro Content Collections — Aucun.
  • Support MCP / Agents : EmDash — Natif. WordPress — Via plugins. Astro Content Collections — Aucun.
  • Déploiement : EmDash — Node.js / Cloudflare. WordPress — LAMP stack. Astro Content Collections — Statique/SSR.
  • Système de plugins : EmDash — API definePlugin(). WordPress — API WP Plugin. Astro Content Collections — N/A.

Liste de Vérification

Après avoir configuré votre instance EmDash, vérifiez ces points :

  • ✅ Panneau admin accessible à /_emdash/admin (200)
  • ✅ Possibilité de créer une nouvelle collection de contenu
  • ✅ L'éditeur de texte riche charge et sauvegarde correctement
  • ✅ L'upload de médias fonctionne (glisser-déposer)
  • ✅ Le site public affiche le contenu du CMS
  • ✅ La génération de types fonctionne : npx emdash types
  • ✅ Le serveur MCP démarre et expose les outils
  • ✅ La connexion Passkey / OAuth fonctionne
  • ✅ L'import WordPress se termine sans erreur

Ressources