# Add EmDash to an existing Astro project

> Configure a Node.js Astro site to edit and query EmDash content locally.

Source: https://emdashcmseverything.com/official-docs/existing-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

Use Astro 6 or later and Node.js 22.16 or later. If the project uses Astro 7.4 or later, use
Node.js 22.23.4 or later. Check both versions in the project:

```bash
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](https://emdashcmseverything.com/official-docs/deployment/cloudflare/).

Commit or otherwise save the current project before changing its configuration.

## Install EmDash

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

#### npm

```bash
npm install emdash @astrojs/node @astrojs/react react react-dom
```

#### pnpm

```bash
pnpm add emdash @astrojs/node @astrojs/react react react-dom
```

#### yarn

```bash
yarn add 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:

   ```js title="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:

   ```ts title="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`:

   ```bash
   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.

## Set up the site and content

1. Start the development server:

   ```bash
   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.

## Query the entry

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

```astro title="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 verification fails

- 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](https://emdashcmseverything.com/official-docs/reference/configuration/) for other databases, storage adapters, and
authentication options. The [Querying content guide](https://emdashcmseverything.com/official-docs/guides/querying-content/) covers filters,
pagination, previews, and cache hints.
