EmDash is designed to run on Cloudflare's infrastructure, but you can also self-host it on any Node.js server. In this guide, we'll walk through both approaches — starting with the recommended Cloudflare deployment, then covering a traditional Node.js setup.

Prerequisites

Before you begin, make sure you have:

  • Node.js 22+ installed (node --version to check)
  • npm or your preferred package manager
  • A Cloudflare account (free tier works) if deploying to Cloudflare
  • A GitHub or GitLab account for Git-based deployments

Option 1: Deploy to Cloudflare (recommended)

This is the fastest path to a live EmDash site. Cloudflare's infrastructure gives you serverless execution, global edge distribution, and automatic scaling — all included in the free tier for most use cases.

Step 1: Create your EmDash project

Open your terminal and run:

npm create emdash@latest

This scaffolds a new EmDash project with the default theme, configuration files, and everything you need to get started. Follow the prompts to name your project and choose your preferences.

Step 2: Explore the project structure

Once created, your project will look something like this:

my-emdash-site/
├── src/
│   ├── pages/        # Astro page routes
│   ├── layouts/      # Shared layout templates
│   └── components/   # Reusable UI components
├── public/           # Static assets
├── seed.json         # Content type definitions
├── astro.config.mjs  # Astro + EmDash configuration
└── package.json

Since EmDash is powered by Astro, the project structure will feel familiar if you've worked with any modern frontend framework.

Step 3: Run locally and test

Start the development server to preview your site:

cd my-emdash-site
npm install
npm run dev

Open http://localhost:4321 in your browser. You should see your EmDash site running with the default theme. The admin panel is available at /admin.

Step 4: Push to GitHub

Create a repository and push your code:

git init
git add .
git commit -m "Initial EmDash site"
git remote add origin https://github.com/your-username/my-emdash-site.git
git push -u origin main

Step 5: Deploy to Cloudflare Pages

  1. Log in to the Cloudflare dashboard
  2. Go to Workers & PagesCreate applicationPages
  3. Connect your GitHub account and select your repository
  4. Configure the build settings:
    • Build command: npm run build
    • Build output directory: dist
    • Node.js version: 22 (set via environment variable NODE_VERSION=22)
  5. Click Save and Deploy

Cloudflare will build your site and deploy it to their global edge network. Within a couple of minutes, your site will be live at your-project.pages.dev.

Step 6: One-click deploy alternative

If you prefer a faster path, you can use the one-click deploy button from the EmDash GitHub repository. This forks the repo to your GitHub account and sets up Cloudflare Pages automatically.

Step 7: Add a custom domain

  1. In the Cloudflare dashboard, go to your Pages project → Custom domains
  2. Click Set up a custom domain
  3. Enter your domain name (e.g., blog.yourdomain.com)
  4. If your domain is already on Cloudflare, DNS records are configured automatically. Otherwise, add the provided CNAME record to your DNS provider.
  5. SSL is provisioned automatically — no configuration needed

Option 2: Self-host on a Node.js server

If you prefer full control over your infrastructure, you can run EmDash on any server that supports Node.js 22+.

Step 1: Create and build your project

npm create emdash@latest
cd my-emdash-site
npm install
npm run build

Step 2: Configure for Node.js

Update your astro.config.mjs to use the Node.js adapter instead of the Cloudflare adapter:

import { defineConfig } from 'astro/config';
import node from '@astrojs/node';

export default defineConfig({
  output: 'server',
  adapter: node({
    mode: 'standalone'
  }),
});

Install the Node.js adapter:

npm install @astrojs/node

Step 3: Build and run

npm run build
node dist/server/entry.mjs

Your EmDash site will start on port 4321 by default. You can configure the port via the PORT environment variable.

Step 4: Set up a reverse proxy

For production, put a reverse proxy like Nginx or Caddy in front of your Node.js process:

# Example Nginx configuration
server {
    listen 80;
    server_name yourdomain.com;

    location / {
        proxy_pass http://localhost:4321;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}

Step 5: Keep it running with a process manager

Use PM2 or systemd to keep your EmDash instance running:

# Using PM2
npm install -g pm2
pm2 start dist/server/entry.mjs --name emdash
pm2 save
pm2 startup

Setting up the admin panel

Regardless of your deployment method, the EmDash admin panel is accessible at /admin. On first visit, you'll set up your admin account using passkey authentication — no passwords needed. From the admin panel you can:

  • Create and manage content
  • Define custom content schemas
  • Upload and organize media
  • Import content from WordPress
  • Install and manage plugins

Importing from WordPress

If you're migrating from WordPress, EmDash makes it straightforward:

  1. In your WordPress admin, go to Tools → Export and download a WXR export file
  2. In your EmDash admin, use the import tool to upload the WXR file
  3. EmDash will automatically migrate your posts, pages, and media

Alternatively, install the EmDash Exporter plugin on your WordPress site for a more seamless migration experience.

Next steps

  • Customize your theme by editing the Astro components in src/
  • Explore the EmDash documentation for advanced configuration
  • Use the EmDash CLI (emdash search, emdash schema create) to manage content programmatically
  • Connect your AI assistant via the built-in MCP server for AI-powered content management

Don't want to manage infrastructure yourself? Sign up for DeployEmDash and we'll handle everything — from SSL certificates to global edge deployment — so you can focus on creating content.