Skip to content

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.

Use Astro 6 or later and Node.js 22.16 or later. Check both versions in the project:

Terminal window
node --version
npx astro --version

This 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.

  1. Install EmDash, the Node.js adapter, and React support:

    Terminal window
    npm install emdash @astrojs/node @astrojs/react react react-dom

    EmDash uses React for the admin panel even when the public site has no React components.

  2. 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 to uploads/ and serves it through EmDash’s media route. Add both paths to .gitignore if they are not already excluded.

  3. Create src/live.config.ts to 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 _emdash entry to its exported collections object instead of replacing the file. A separate src/content.config.ts for file-based collections continues to work alongside it.

  4. Generate a local encryption key and write it to .env:

    Terminal window
    npx emdash secrets generate --write .env

    Confirm that .env is 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.

  1. Start the development server:

    Terminal window
    npm run dev
  2. 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.

  3. Open Posts, select New Post, and enter EmDash is connected as 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.

Create a server-rendered test page that lists the published posts:

src/pages/emdash-test.astro
---
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 the admin remains on Loading EmDash…, check that react() appears in the Astro integrations array. Installing @astrojs/react without registering it is not enough.
  • If getEmDashCollection() returns an error about the live collection, check that src/live.config.ts exports _emdash with emdashLoader().
  • 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.