The EmDash CLI provides commands for managing an EmDash CMS instance — database setup, type generation, content CRUD, schema management, media, and more.
Installation
The CLI is included with the emdash package. Install it with the following command:
npm install emdash
Run commands with npx emdash or add scripts to package.json. The binary is also available as em for brevity.
Authentication
Commands that talk to a running EmDash instance resolve authentication in this order:
--tokenflag — explicit token on the command lineEMDASH_TOKENenv var- Stored credentials from
~/.config/emdash/auth.json(saved byemdash login) - Dev bypass — if the URL is localhost and no token is available, automatically authenticates via the dev bypass endpoint
Most commands accept --url (default http://localhost:4321) and --token flags. When targeting a local dev server, no token is needed.
Common Flags
These flags are available on all remote commands:
| Flag | Alias | Description | Default |
|---|---|---|---|
--url | -u | EmDash instance URL | http://localhost:4321 |
--token | -t | Auth token | From env/stored creds |
--json | Output as JSON (for piping) | Auto-detected from TTY |
Output
When stdout is a TTY, the CLI pretty-prints results with consola. When piped or when --json is set, it outputs raw JSON to stdout — suitable for jq or other tools.
Commands
emdash dev
Start the development server with automatic database setup.
npx emdash dev [options]
Options
| Option | Alias | Description | Default |
|---|---|---|---|
--database | -d | Database file path | ./data.db |
--types | -t | Generate types from remote before starting | false |
--port | -p | Dev server port | 4321 |
--cwd | Working directory | Current directory |
Examples
# Start dev server
npx emdash dev
# Custom port
npx emdash dev --port 3000
# Generate types from remote before starting
npx emdash dev --types
Behavior
- Checks for and runs pending database migrations
- If
--typesis set, generates TypeScript types from a remote instance (URL fromEMDASH_URLenv oremdash.urlinpackage.json) - Starts Astro dev server with
EMDASH_DATABASE_URLset
emdash types
Generate TypeScript types from a running EmDash instance’s schema.
npx emdash types [options]
Options
| Option | Alias | Description | Default |
|---|---|---|---|
--url | -u | EmDash instance URL | http://localhost:4321 |
--token | -t | Auth token | From env/stored creds |
--output | -o | Output path for types | .emdash/types.ts |
--cwd | Working directory | Current directory |
Examples
# Generate types from local dev server
npx emdash types
# Generate from remote instance
npx emdash types --url https://my-site.pages.dev
# Custom output path
npx emdash types --output src/types/emdash.ts
Behavior
- Fetches the schema from the instance
- Generates TypeScript type definitions
- Writes types to the output file
- Writes
schema.jsonalongside for reference
emdash login
Log in to an EmDash instance using OAuth Device Flow.
npx emdash login [options]
Options
| Option | Alias | Description | Default |
|---|---|---|---|
--url | -u | EmDash instance URL | http://localhost:4321 |
Behavior
- Discovers auth endpoints from the instance
- If localhost and no auth configured, uses dev bypass automatically
- Otherwise initiates OAuth Device Flow — displays a code and opens your browser
- Polls for authorization, then saves credentials to
~/.config/emdash/auth.json
Saved credentials are used automatically by all subsequent commands targeting the same instance.
emdash logout
Log out and remove stored credentials.
npx emdash logout [options]
Options
| Option | Alias | Description | Default |
|---|---|---|---|
--url | -u | EmDash instance URL | http://localhost:4321 |
emdash whoami
Show the current authenticated user.
npx emdash whoami [options]
Options
| Option | Alias | Description | Default |
|---|---|---|---|
--url | -u | EmDash instance URL | http://localhost:4321 |
--token | -t | Auth token | From env/stored creds |
--json | Output as JSON |
Displays email, name, role, auth method, and instance URL.
emdash content
Manage content items. All subcommands use the remote API via EmDashClient.
content list <collection>
npx emdash content list posts
npx emdash content list posts --status published --limit 10
| Option | Description |
|---|---|
--status | Filter by status |
--limit | Maximum items |
--cursor | Pagination cursor |
content get <collection> <id>
npx emdash content get posts 01ABC123
npx emdash content get posts 01ABC123 --raw
| Option | Description |
|---|---|
--raw | Return raw Portable Text (skip markdown conversion) |
The response includes a _rev token. Pass it to content update to confirm you have seen the current state before overwriting it.
content create <collection>
npx emdash content create posts --data '{"title": "Hello"}'
npx emdash content create posts --file post.json --slug hello-world
cat post.json | npx emdash content create posts --stdin
| Option | Description |
|---|---|
--data | JSON string with content data |
--file | Read data from a JSON file |
--stdin | Read data from stdin |
--slug | Content slug |
--locale | Content locale |
--translation-of | ID of a content item to link this as a translation of |
--draft | Keep as draft instead of auto-publishing |
Provide data via exactly one of --data, --file, or --stdin. New items are auto-published unless --draft is set.
content update <collection> <id>
You must provide the _rev token from a prior get to prove you have seen the current state. This prevents overwriting changes you have not seen. The following steps read an item, then update it with that token:
# 1. Read the item, note the _rev
npx emdash content get posts 01ABC123
# 2. Update with the _rev from step 1
npx emdash content update posts 01ABC123 \
--rev MToyMDI2LTAyLTE0... \
--data '{"title": "Updated"}'
| Option | Description |
|---|---|
--rev | Revision token from get (required) |
--data | JSON string with content data |
--file | Read data from a JSON file |
If the item has changed since your get, the server returns 409 Conflict — re-read and try again.
content delete <collection> <id>
npx emdash content delete posts 01ABC123
Soft-deletes the content item (moves to trash).
content publish <collection> <id>
npx emdash content publish posts 01ABC123
content unpublish <collection> <id>
npx emdash content unpublish posts 01ABC123
content schedule <collection> <id>
npx emdash content schedule posts 01ABC123 --at 2026-03-01T09:00:00Z
| Option | Description |
|---|---|
--at | ISO 8601 datetime (required) |
content restore <collection> <id>
npx emdash content restore posts 01ABC123
Restores a trashed content item.
emdash schema
Manage collections and fields.
schema list
npx emdash schema list
Lists all collections.
schema get <collection>
npx emdash schema get posts
Shows a collection with all its fields.
schema create <collection>
npx emdash schema create articles --label Articles
npx emdash schema create articles --label Articles --label-singular Article --description "Blog articles"
| Option | Description |
|---|---|
--label | Collection label (required) |
--label-singular | Singular label |
--description | Collection description |
schema delete <collection>
npx emdash schema delete articles
npx emdash schema delete articles --force
| Option | Description |
|---|---|
--force | Skip confirmation |
Prompts for confirmation unless --force is set.
schema add-field <collection> <field>
npx emdash schema add-field posts body --type portableText --label "Body Content"
npx emdash schema add-field posts featured --type boolean --required
| Option | Description |
|---|---|
--type | Field type: string, text, number, integer, boolean, datetime, image, reference, portableText, json (required) |
--label | Field label (defaults to field slug) |
--required | Whether the field is required |
schema remove-field <collection> <field>
npx emdash schema remove-field posts featured
emdash media
Manage media items.
media list
npx emdash media list
npx emdash media list --mime image/png --limit 20
| Option | Description |
|---|---|
--mime | Filter by MIME type |
--limit | Number of items |
--cursor | Pagination cursor |
media upload <file>
npx emdash media upload ./photo.jpg
npx emdash media upload ./photo.jpg --alt "A sunset" --caption "Taken in Bristol"
| Option | Description |
|---|---|
--alt | Alt text |
--caption | Caption text |
media get <id>
npx emdash media get 01MEDIA123
media delete <id>
npx emdash media delete 01MEDIA123
emdash search
Full-text search across content.
npx emdash search "hello world"
npx emdash search "hello" --collection posts --limit 5
| Option | Alias | Description |
|---|---|---|
--collection | -c | Filter by collection |
--limit | -l | Maximum results |
emdash taxonomy
Manage taxonomies and terms.
taxonomy list
npx emdash taxonomy list
taxonomy terms <name>
npx emdash taxonomy terms categories
npx emdash taxonomy terms tags --limit 50
| Option | Alias | Description |
|---|---|---|
--limit | -l | Maximum terms |
--cursor | Pagination cursor |
taxonomy add-term <taxonomy>
npx emdash taxonomy add-term categories --name "Tech" --slug tech
npx emdash taxonomy add-term categories --name "Frontend" --parent 01PARENT123
| Option | Description |
|---|---|
--name | Term label (required) |
--slug | Term slug (defaults to slugified name) |
--parent | Parent term ID (for hierarchical taxonomies) |
emdash menu
Manage navigation menus.
menu list
npx emdash menu list
menu get <name>
npx emdash menu get primary
Returns the menu with all its items.
emdash export-seed
Export database schema and content as a seed file. Works directly on a local SQLite file.
npx emdash export-seed [options] > seed.json
Options
| Option | Alias | Description | Default |
|---|---|---|---|
--database | -d | Database file path | ./data.db |
--cwd | Working directory | Current directory | |
--with-content | Include content (all or comma-separated collections) | ||
--no-pretty | Disable JSON formatting | false |
Output Format
The exported seed file includes:
- Settings: Site title, tagline, social links
- Collections: All collection definitions with fields
- Taxonomies: Taxonomy definitions and terms
- Menus: Navigation menus with items
- Widget Areas: Widget areas and widgets
- Content (if requested): Entries with
$mediareferences and$ref:syntax for portability
emdash secrets generate
Generate an EMDASH_ENCRYPTION_KEY for your deployment. The key is used to
encrypt plugin secrets at rest.
npx emdash secrets generate
Prints the new key to stdout. Pipe it into your secret store, or write it
straight to a dev file with --write. The following commands write the key to .dev.vars or .env:
npx emdash secrets generate --write .dev.vars
npx emdash secrets generate --write .env
--write refuses to overwrite an existing entry without --force.
Replacing a key in a deployment with existing encrypted data will leave
those secrets unreadable, so the protection is intentional.
emdash secrets fingerprint <key>
Print the 8-character fingerprint (kid) of a key without exposing its value. This is useful in CI for verifying the right key was deployed. The following command prints a key’s fingerprint:
npx emdash secrets fingerprint emdash_enc_v1_...
Generated Files
.emdash/types.ts
The emdash types command generates TypeScript interfaces for each collection:
// Generated by EmDash CLI
// Do not edit manually - run `emdash types` to regenerate
import type { PortableTextBlock } from "emdash";
export interface Post {
id: string;
title: string;
content: PortableTextBlock[];
publishedAt: Date | null;
}
.emdash/schema.json
The command also writes a raw schema export for tooling:
{
"version": "a1b2c3d4",
"collections": [
{
"slug": "posts",
"label": "Posts",
"fields": [...]
}
]
}
Environment Variables
| Variable | Description |
|---|---|
EMDASH_DATABASE_URL | Database URL (set automatically by dev) |
EMDASH_TOKEN | Auth token for remote operations |
EMDASH_URL | Default remote URL for types and dev --types |
EMDASH_ENCRYPTION_KEY | Key for encrypting plugin secrets at rest. Operator-provided — never stored in the database. Generate with emdash secrets generate. |
EMDASH_PREVIEW_SECRET | Optional override for preview HMAC secret. When unset, EmDash generates and persists one in the options table. |
EMDASH_IP_SALT | Optional override for the commenter-IP hash salt. When unset, EmDash generates and persists one in the options table. |
EMDASH_AUTH_SECRET | Legacy. Used as the IP-salt source if set, so existing installs keep stable commenter-IP hashes across upgrade. New installs should not set this. |
Package scripts
Add the CLI commands as package.json scripts for convenience:
{
"scripts": {
"dev": "emdash dev",
"types": "emdash types",
"export-seed": "emdash export-seed",
"db:reset": "rm -f data.db"
}
}
Exit Codes
| Code | Description |
|---|---|
0 | Success |
1 | Error (configuration, network, database) |