EmDash CMS. Setting up and using EmDash CMS with your Lexington theme
Some Lexington themes are available with EmDash CMS integration. These variants ship as a single Astro project with a built-in admin at /_emdash/admin, so editors can manage content without a separate Studio deploy: while developers keep Astro performance and full control of the front end.
Local development uses Node.js and SQLite. Production deploys to Cloudflare Workers with D1 and R2.
Quick Start (Local)
The whole flow: install, seed sample content, start the site and CMS:
After downloading or forking your theme:
npm install
npm run setup # sample content + images (first time)
npm run devEach EmDash theme runs on its own dev port (for example, Semplice uses 4335), so it never conflicts with other Astro projects. The dev server prints the exact URLs when it starts:
- Website →
http://localhost:<port> - CMS admin →
http://localhost:<port>/_emdash/admin
Or open admin with the dev login shortcut:
npm run adminEdit content in admin, click Save, then Publish. Drafts do not appear on the site until published.
Prerequisites
- Node.js v22.12.0 or higher: Download here
- npm: included with Node.js
- Cloudflare account: only required for production deploy
Editing Content
- Go to
/_emdash/admin(or runnpm run adminlocally). - Open a collection: posts, podcast episodes, jobs, help articles, etc. (depends on your theme).
- Edit fields and upload media as needed.
- Click Save, then Publish.
- Refresh the website to see live changes.
Menus
Navigation is CMS-managed in most EmDash themes:
- Admin → Appearance → Menus
- Edit
primary,company,footer, or other seeded menu keys - Publish changes
Search
EmDash themes with LiveSearch use the built-in API at /_emdash/api/search. Press ⌘K / Ctrl+K on the site to open search.
Site settings
Admin → Settings → Site Settings: set site URL, SEO defaults, and social handles. See your theme’s SEO.md for details.
Deploy to Cloudflare
The key steps on camera: store the encryption key, verify the build, deploy:
Complete this checklist before going live. The theme ships with placeholders you must replace:
| What | File | Action |
|---|---|---|
| Site URL | astro.config.shared.mjs |
Set site to your production URL |
| Site URL (CMS) | Admin → Settings → Site Settings | Set the same URL after deploy |
| R2 public URL | astro.config.cloudflare.mjs |
Uncomment and set publicUrl on the r2() adapter |
| KV cache id | wrangler.jsonc |
Replace REPLACE_WITH_KV_NAMESPACE_ID |
Step 1: Set your domain
astro.config.shared.mjs: setsite(e.g.https://example.com).wrangler.jsonc: setnameto your Worker name.- After deploy, set the same URL in admin → Settings → Site Settings.
Step 2: Encryption key (required)
EmDash encrypts sensitive data at rest. Generate once and store a backup.
npx wrangler login
npx emdash secrets generate
npx wrangler secret put EMDASH_ENCRYPTION_KEYPaste the generated key when prompted.
Step 3: KV cache namespace (recommended)
KV caches menus, settings, and queries for faster pages.
npx wrangler kv namespace create site-cacheCopy the returned id into wrangler.jsonc → kv_namespaces[0].id.
Local dev uses in-memory cache automatically.
Step 4: R2 public media URL (required for images)
CMS images are stored in R2 in production:
- Cloudflare dashboard → R2 → your media bucket → Settings → Public access
- Uncomment and set
publicUrlinastro.config.cloudflare.mjs:
storage: r2({
binding: "MEDIA",
publicUrl: "https://media.yourdomain.com",
}),- Redeploy:
npm run deploy
See EmDash Cloudflare deployment.
Step 5: Build and deploy
npm run check:cf # optional: verify production build
npm run deployStep 6: Complete Setup Wizard
Open https://<your-worker>.workers.dev/_emdash/admin and complete the Setup Wizard. You’ll create a real admin login with a passkey; the local dev login shortcut doesn’t exist in production.
Seed content runs on the live Worker; your local SQLite database is not deployed.
Step 7: Custom domain
Cloudflare dashboard → Workers & Pages → your worker → Custom Domains → Add.
Update site in astro.config.shared.mjs and Site URL in admin to match.
Project Structure
/
├── .emdash/
│ ├── seed.json # Content model + sample entries
│ └── uploads/ # Seeded media
├── src/
│ ├── components/
│ ├── layouts/
│ ├── lib/ # CMS helpers (menus, settings, etc.)
│ ├── pages/
│ └── styles/
├── scripts/
│ ├── apply-media.mjs # Links seed images (part of setup)
│ └── clean.sh # Distribution cleanup
├── astro.config.mjs # Local dev (Node + SQLite)
├── astro.config.cloudflare.mjs # Production (Workers + D1 + R2)
├── astro.config.shared.mjs # Shared site URL and settings
└── wrangler.jsonc # Cloudflare Worker configContent types and routes vary by theme. Check .emdash/seed.json and src/content.config.ts in your theme for the exact schema.
Customization
Styling
Edit src/styles/global.css for global styles. Lexington EmDash themes use Tailwind CSS v4.
Content model
The CMS schema lives in .emdash/seed.json. After changing fields or collections, re-seed locally if needed:
npm run setupFor production schema changes, follow EmDash documentation for migrations and deploy steps.
Portable Text
Rich text fields render through Portable Text components in your theme. Extend block types in the admin schema and matching Astro components on the front end.
Troubleshooting
“Cannot find module” errors?
npm installEmpty site / no posts?
npm run setup
npm run devImages missing after setup?
node scripts/apply-media.mjs(or run npm run setup, which includes this step)
Edits not showing on the website?
- Click Publish in admin after Save (not just Save).
- Hard-refresh the browser.
Admin save errors or dev server stuck?
npm run stop
npm run devPort already in use?
npm run stop
npm run devImages broken in production?
- Confirm R2 public access is enabled.
- Set
publicUrlinastro.config.cloudflare.mjsand redeploy.
Slow pages in production?
- Create a KV namespace and set its id in
wrangler.jsonc.
Useful Commands
| Command | Description |
|---|---|
npm install |
Install dependencies |
npm run setup |
Seed content + link sample images |
npm run dev |
Start local site + CMS (SQLite) |
npm run admin |
Open admin with local dev login |
npm run stop |
Stop the theme’s dev server |
npm run check:cf |
Verify production build (no deploy) |
npm run deploy |
Build and deploy to Cloudflare Workers |
npm run clean |
Remove node_modules, caches, local DB before sharing |