Add EmDash to an existing Astro project
This guide adds EmDash to an Astro project and verifies the integration with one published entry. It uses the Node.js adapter, SQLite, and local media storage so the complete path works on one machine.
Before you start
Section titled “Before you start”Use Astro 6 or later and Node.js 22.16 or later. Check both versions in the project:
node --versionnpx astro --versionThis guide changes the site to Astro’s server output and configures the Node.js adapter. That
changes how the site is built and deployed. If the project already uses another server adapter, do
not add a second one. Keep that adapter and follow its deployment requirements; for Cloudflare, use
the Cloudflare Workers guide.
Commit or otherwise save the current project before changing its configuration.
Install EmDash
Section titled “Install EmDash”-
Install EmDash, the Node.js adapter, and React support:
Terminal window npm install emdash @astrojs/node @astrojs/react react react-domTerminal window pnpm add emdash @astrojs/node @astrojs/react react react-domTerminal window yarn add emdash @astrojs/node @astrojs/react react react-domEmDash uses React for the admin panel even when the public site has no React components.
-
Register the adapter, React, and EmDash in
astro.config.mjs. If the file already contains other integrations or settings, keep them and add the relevant entries from this example:astro.config.mjs import node from "@astrojs/node";import react from "@astrojs/react";import { defineConfig } from "astro/config";import emdash, { local } from "emdash/astro";import { sqlite } from "emdash/db";export default defineConfig({output: "server",adapter: node({ mode: "standalone" }),integrations: [react(),emdash({database: sqlite({ url: "file:./data.db" }),storage: local({directory: "./uploads",baseUrl: "/_emdash/api/media/file",}),}),],});SQLite stores the content and content model in
data.db. The local storage adapter writes media touploads/and serves it through EmDash’s media route. Add both paths to.gitignoreif they are not already excluded. -
Create
src/live.config.tsto connect EmDash to Astro’s content system:src/live.config.ts import { defineLiveCollection } from "astro:content";import { emdashLoader } from "emdash/runtime";export const collections = {_emdash: defineLiveCollection({ loader: emdashLoader() }),};If the project already has
src/live.config.ts, add the_emdashentry to its exportedcollectionsobject instead of replacing the file. A separatesrc/content.config.tsfor file-based collections continues to work alongside it. -
Generate a local encryption key and write it to
.env:Terminal window npx emdash secrets generate --write .envConfirm that
.envis excluded by.gitignore. The key protects plugin secrets stored in the database. Replacing or losing it makes those encrypted values unreadable, so keep a protected backup before deploying the site.
Set up the site and content
Section titled “Set up the site and content”-
Start the development server:
Terminal window npm run dev -
Open
http://localhost:4321/_emdash/admin/. The first visit redirects to the setup wizard. Enter the site details, create the administrator account, and register a passkey.Because this project has no seed file, setup applies EmDash’s built-in starting model. It creates Posts and Pages collections, Title and content fields, and Category and Tag taxonomies. It does not add sample entries.
-
Open Posts, select New Post, and enter
EmDash is connectedas the title. Select Save to create the entry, then select Publish.
The database now contains one published entry in the built-in posts collection. The next step
reads it from an Astro page.
Query the entry
Section titled “Query the entry”Create a server-rendered test page that lists the published posts:
---import { getEmDashCollection } from "emdash";
const { entries: posts, error } = await getEmDashCollection("posts");
if (error) { throw error;}---
<h1>EmDash posts</h1><ul> {posts.map((post) => <li>{post.data.title}</li>)}</ul>Open http://localhost:4321/emdash-test/. The page displays EmDash is connected. If you change
and republish the title in the admin panel, reloading this page displays the updated title.
During local development, EmDash also generates emdash-env.d.ts from the current content model.
The generated declarations give TypeScript the posts collection name and its title field. Do
not edit that generated file by hand.
If verification fails
Section titled “If verification fails”- If the admin remains on Loading EmDash…, check that
react()appears in the Astrointegrationsarray. Installing@astrojs/reactwithout registering it is not enough. - If
getEmDashCollection()returns an error about the live collection, check thatsrc/live.config.tsexports_emdashwithemdashLoader(). - If the page works in development but deployed edits do not appear, check that the page is not prerendered and that the deployed application uses server output.
- If the build cannot resolve one of the imports, rerun the install command and confirm that the five packages were added to this project rather than another workspace directory.
Read Configuration for other databases, storage adapters, and authentication options. The Querying content guide covers filters, pagination, previews, and cache hints.