Getting Started

On this page

This guide walks you through creating your first EmDash site, from installation to publishing your first post.

Prerequisites

  • Node.js v22.12.0 or higher (odd-numbered versions are not supported)
  • npm, pnpm, or yarn
  • A code editor (VS Code recommended)

Create a New Project

npm

npm create emdash@latest

pnpm

pnpm create emdash@latest

yarn

yarn create emdash

Follow the prompts to name your project and set up your preferences.

Start the Development Server

  1. Navigate to your project directory:

    cd my-emdash-site
  2. Install dependencies:

    npm install
  3. Start the dev server:

    npm run dev
  4. Open your browser to http://localhost:4321

Complete the Setup Wizard

When you first visit the admin panel, EmDash’s Setup Wizard guides you through initial configuration:

  1. Navigate to http://localhost:4321/_emdash/admin

  2. You’ll be redirected to the Setup Wizard. Enter:

    • Site Title — Your site’s name
    • Tagline — A short description
    • Admin Email — Your email address
  3. Click Create Site to register your passkey

  4. Your browser will prompt you to create a passkey using Touch ID, Face ID, Windows Hello, or a security key

Once your passkey is registered, you’re logged in and redirected to the admin dashboard.

EmDash admin dashboard showing content overview, recent activity, and navigation sidebar

Your First Post

  1. In the admin sidebar, click Posts under Content.

  2. Click New Post.

  3. Enter a title and write some content using the rich text editor.

    EmDash post editor with rich text toolbar and publish sidebar
  4. Set the status to Published and click Save.

  5. Visit your site’s homepage to see your post live—no rebuild needed!

Project Structure

Your EmDash project follows a standard Astro structure with a few additions:

my-emdash-site/
├── astro.config.mjs      # Astro + EmDash configuration
├── src/
│   ├── live.config.ts    # Live Collections configuration
│   ├── pages/
│   │   ├── index.astro   # Homepage
│   │   └── posts/
│   │       └── [...slug].astro  # Dynamic post pages
│   ├── layouts/
│   │   └── Base.astro    # Base layout
│   └── components/       # Your Astro components
├── .emdash/
│   ├── seed.json         # Template seed file
│   └── types.ts          # Generated TypeScript types
└── package.json

Configuration Files

astro.config.mjs

This configures EmDash as an Astro integration:

import { defineConfig } from "astro/config";
import emdash, { local } from "emdash/astro";
import { sqlite } from "emdash/db";

export default defineConfig({
	integrations: [
		emdash({
			database: sqlite({ url: "file:./data.db" }),
			storage: local({
				directory: "./uploads",
				baseUrl: "/_emdash/api/media/file",
			}),
		}),
	],
});

src/live.config.ts

This connects EmDash to Astro’s content system:

import { defineLiveCollection } from "astro:content";
import { emdashLoader } from "emdash/runtime";

export const collections = {
	_emdash: defineLiveCollection({ loader: emdashLoader() }),
};

Environment Variables

For production deployments, you’ll need to set:

# Required for authentication
EMDASH_AUTH_SECRET=your-secret-here

# Optional: for content preview
EMDASH_PREVIEW_SECRET=your-preview-secret

Generate a secure auth secret with:

npx emdash auth secret

Query Content in Pages

Use EmDash’s query functions in your Astro pages. These follow Astro’s live collections pattern, returning { entries, error } for collections and { entry, error } for single entries:

---
import { getEmDashCollection } from "emdash";
import Base from "../layouts/Base.astro";

const { entries: posts } = await getEmDashCollection("posts");
---

<Base title="Home">
  <h1>Latest Posts</h1>
  <ul>
    {posts.map((post) => (
      <li>
        <a href={`/posts/${post.slug}`}>{post.data.title}</a>
      </li>
    ))}
  </ul>
</Base>

For single entries:

---
import { getEmDashEntry } from "emdash";

const { slug } = Astro.params;
const { entry: post } = await getEmDashEntry("posts", slug);

if (!post) {
  return Astro.redirect("/404");
}
---

<h1>{post.data.title}</h1>

Generate TypeScript Types

For full type safety, generate types from your database schema:

npx emdash types

This creates .emdash/types.ts with interfaces for all your collections. Your editor will now autocomplete field names and catch type errors.

Next Steps

You now have a working EmDash site! Here’s where to go next: