CLI Reference

On this page

The EmDash CLI provides commands for database setup, type generation, creating and editing content, schema management, media, site export and import, and plugin development.

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.

Start your site with its package script, such as pnpm dev. The package script starts Astro; the EmDash integration generates emdash-env.d.ts, while the runtime runs pending migrations on the first request and applies the bundled seed when the database is empty and setup has not been completed.

Authentication

Commands that connect to a running EmDash instance resolve authentication in this order:

  1. --token flag — explicit token on the command line
  2. EMDASH_TOKEN env var
  3. Stored credentials from ~/.config/emdash/auth.json (saved by emdash login)
  4. Dev bypass — if the URL is localhost and no token is available, automatically authenticates via the dev bypass endpoint

The types, whoami, content, schema, media, search, taxonomy, menu, and site commands connect to a running instance. Authentication commands have their own connection options. When targeting a local development server, no token is needed.

Common flags

Connection flags vary by command. The grouped commands below mean every subcommand in that group.

FlagAliasAvailable onDescription and default
--url-utypes, login, logout, whoami, content, schema, media, search, taxonomy, menu, siteInstance URL; defaults to EMDASH_URL or http://localhost:4321
--token-ttypes, whoami, content, schema, media, search, taxonomy, menu, siteToken from the flag, EMDASH_TOKEN, or stored credentials
--header "Name: Value"-Htypes, login, content, schema, media, search, taxonomy, menu, siteRepeatable header merged with EMDASH_HEADERS and stored headers
--jsonwhoami, content, schema, media, search, taxonomy, menu, siteWrite raw JSON instead of terminal-formatted output

Output

When a command writes results to an interactive terminal, it formats them for reading. The commands listed with --json above write raw JSON when the flag is set or their output is piped. emdash migrate emits JSON only with its explicit --json option.

Commands

emdash init

Initialize a local SQLite database from the template metadata in package.json. The command runs core migrations, then applies the optional SQL file named by emdash.schema. Run emdash seed separately for JSON seed data.

npx emdash init [options]
OptionAliasDescriptionDefault
--database-dSQLite database path./data.db
--cwdProject working directoryCurrent directory
--force-fReapply the template schema when collections already existfalse

Without --force, an initialized database is left unchanged. This command opens a local SQLite file directly; use emdash migrate for deployment-managed D1, PostgreSQL, libSQL, or Hyperdrive migrations.

emdash doctor

Check a local SQLite database for connection, migration, collection, table, and user problems. If the project has a Wrangler configuration, the command also checks that a Cron Trigger and EmDash scheduled() handler are configured together.

npx emdash doctor [options]
OptionAliasDescriptionDefault
--database-dSQLite database path./data.db
--cwdProject working directoryCurrent directory
--jsonEmit structured resultsfalse

The command reports each check as pass, warning, or failure and exits non-zero when a check fails.

emdash seed

Validate or apply a JSON seed to a local SQLite database. The command uses the positional path when provided, then .emdash/seed.json, then the emdash.seed path from package.json.

npx emdash seed [path] [options]
OptionAliasDescriptionDefault
--database-dSQLite database path./data.db
--cwdProject working directoryCurrent directory
--validateValidate the seed without changing the databasefalse
--no-contentSkip entries, bylines, and taxonomy termsfalse
--on-conflictHandle existing records with skip, update, or errorskip
--uploads-dirLocal directory used for seed media./uploads
--media-base-urlBase URL stored for local seed media/_emdash/api/media/file

Applying a seed runs core migrations first. Use --validate in continuous integration when you need to check the file without opening or creating the database.

emdash migrate

Check or apply the core migration set emitted by an Astro build.

npx emdash migrate [options]
npx emdash migrate --check [options]
npx emdash migrate --status --json [options]
npx emdash migrate --release-lock <id> [options]

By default the command discovers the project root and reads .emdash/migrations.json. It validates the manifest against the project’s installed EmDash package, resolves the adapter’s project-local executor, and prints the immutable target before any SQL.

Options

OptionDescription
--checkApply nothing; exit non-zero for pending or unknown migration records
--statusReport exact status without applying; exit zero after a successful report
--jsonEmit the stable migration report as JSON
--manifest <path>Read a non-standard manifest path
--from-configExplicitly evaluate trusted Astro configuration instead of a manifest
--config <path>Astro config path used with --from-config
--expected-target-fingerprint <sha256>Required guard for non-interactive apply or lock release
--release-lock <id>Release the D1 migration lock with the id that --status reports; cannot be combined with --check or --status
--database <path>Override a SQLite path
--database-url-env <name>Override a PostgreSQL connection-variable name
--d1 <uuid-or-name>Select a D1 database explicitly
--account-id <id>Select a Cloudflare account explicitly
--wrangler-config <path>Read D1 binding metadata from an explicit Wrangler config
--wrangler-env <name>Select an environment; requires --wrangler-config

Interactive human-readable apply and lock release ask for confirmation. Non-interactive apply or lock release, and every apply or lock release using --json, require the exact fingerprint printed for the target. There is no down or --dry-run; use --check to determine whether work is required.

Exit codes

CodeMeaning
0Success, including a successful --status report
1Validation, configuration, target, migration, or cleanup error
2--check found pending known migrations
3--check found unknown applied records (takes precedence over pending)
4Confirmation missing, declined, or target fingerprint mismatch
130Interrupted after bounded executor cleanup

See Manage Core Database Migrations for deployment order, target credentials, and the D1 migration lock.

emdash dev (deprecated)

The legacy command initializes and migrates a local SQLite database before starting Astro. That behavior does not use the database adapter configured by the site and is incompatible with Cloudflare D1 development. Existing invocations now print a deprecation warning before doing any database work.

OptionAliasDescriptionDefault
--database-dLocal SQLite database path./data.db
--types-tFetch remote types before starting Astrofalse
--port-pAstro development-server port4321
--cwdProject working directoryCurrent directory

emdash types

Generate TypeScript types from a running EmDash instance’s schema.

npx emdash types [options]

Options

OptionAliasDescriptionDefault
--url-uEmDash instance URLhttp://localhost:4321
--token-tAuth tokenFrom env or stored credentials
--header-HCustom request header; repeatableFrom env or stored credentials
--jsonAccepted but does not change this command’s files or progress output—
--output-oOutput path for types.emdash/types.ts
--cwdWorking directoryCurrent 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

  1. Fetches the schema from the instance
  2. Generates TypeScript type definitions
  3. Writes types to the output file
  4. Writes schema.json alongside for reference

emdash login

Log in to an EmDash instance using OAuth Device Flow.

npx emdash login [options]

Options

OptionAliasDescriptionDefault
--url-uEmDash instance URLhttp://localhost:4321
--header-HCustom request header; repeatableFrom EMDASH_HEADERS

Behavior

  1. Discovers auth endpoints from the instance
  2. If localhost and no auth configured, uses dev bypass automatically
  3. Otherwise initiates OAuth Device Flow — displays a code and opens your browser. After you enter the code, the admin page lists the permissions the CLI will receive, and any requested permissions your role does not allow, before you approve.
  4. 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

OptionAliasDescriptionDefault
--url-uEmDash instance URLhttp://localhost:4321

emdash whoami

Show the current authenticated user.

npx emdash whoami [options]

Options

OptionAliasDescriptionDefault
--url-uEmDash instance URLhttp://localhost:4321
--token-tAuth tokenFrom env/stored creds
--jsonOutput 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
OptionDescription
--statusFilter by status
--localeFilter by locale
--limitMaximum items
--cursorPagination cursor

content get <collection> <id>

npx emdash content get posts 01ABC123
npx emdash content get posts 01ABC123 --raw
OptionDescription
--localeLocale to use when the ID argument is a slug
--rawReturn raw Portable Text instead of Markdown
--publishedIgnore a pending draft and return published data only

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
OptionDescription
--dataJSON string with content data
--fileRead data from a JSON file
--stdinRead data from stdin
--slugContent slug
--localeContent locale
--translation-ofID of a content item to link this as a translation of
--draftKeep 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"}'
OptionDescription
--revRevision token from get (required)
--dataJSON string with content data
--fileRead data from a JSON file
--localeLocale to use when the ID argument is a slug
--draftKeep the update as a draft instead of auto-publishing
--override-lockWrite even though another editor has the entry open

If the item has changed since your get, the server returns 409 Conflict — re-read and try again.

If someone has the entry open in the admin, the server returns 409 with code ENTRY_LOCKED and a message that names the holder. Wait for them to finish, or pass --override-lock. The same flag is available on content delete, content publish, content unpublish and content schedule.

content delete <collection> <id>

npx emdash content delete posts 01ABC123

Soft-deletes the content item (moves to trash).

Pass --override-lock to delete an entry that another editor has open.

content publish <collection> <id>

npx emdash content publish posts 01ABC123

Pass --override-lock to publish an entry that another editor has open.

content unpublish <collection> <id>

npx emdash content unpublish posts 01ABC123

Pass --override-lock to unpublish an entry that another editor has open.

content schedule <collection> <id>

npx emdash content schedule posts 01ABC123 --at 2026-03-01T09:00:00Z
OptionDescription
--atISO 8601 datetime with Z or an explicit UTC offset (required)

Pass --override-lock to schedule an entry that another editor has open.

content restore <collection> <id>

npx emdash content restore posts 01ABC123

Restores a trashed content item.

content translations <collection> <id>

List every translation in the entry’s translation group:

npx emdash content translations posts 01ABC123

The result includes each translation’s ID, locale, slug, status, and whether it is the requested entry.

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"
OptionDescription
--labelCollection label (required)
--label-singularSingular label
--descriptionCollection description

schema delete <collection>

npx emdash schema delete articles
npx emdash schema delete articles --force
OptionDescription
--forceSkip 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
OptionDescription
--typeField type: string, text, url, number, integer, boolean, datetime, select, multiSelect, portableText, image, file, reference, json, slug, or repeater (required)
--labelField label (defaults to field slug)
--requiredWhether 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
OptionDescription
--mimeFilter by MIME type
--limitNumber of items
--cursorPagination cursor

media upload <file>

npx emdash media upload ./photo.jpg
npx emdash media upload ./photo.jpg --alt "A sunset" --caption "Taken in Bristol"
OptionDescription
--altAlt text
--captionCaption text

media get <id>

npx emdash media get 01MEDIA123

media delete <id>

npx emdash media delete 01MEDIA123

media repair-usage

Repair content media usage indexes for one collection or for every content collection. Use this after imports or direct database writes when usage coverage is stale or untrusted.

npx emdash media repair-usage --collection posts
npx emdash media repair-usage --all
npx emdash media repair-usage --all --json
OptionAliasDescription
--collection-cRepair one content collection
--allRepair every content collection

Pass exactly one of --collection or --all. Remote repair requires an Admin user and an auth token with the admin scope.

All-content repair runs synchronously and can be slow or expensive on large sites. Prefer --collection when you only need to repair one collection.

Structured complete, partial, and stale repair results exit 0; structured failed results exit 1. Automation and cron jobs should use --json and parse status, failedSourceCount, skippedSourceCount, and per-collection summaries instead of treating exit 0 as complete coverage.

Full-text search across content.

npx emdash search "hello world"
npx emdash search "hello" --collection posts --limit 5
OptionAliasDescription
--collection-cFilter by collection
--localeFilter by locale
--limit-lMaximum 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
OptionAliasDescription
--limit-lMaximum terms
--cursorPagination 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
OptionDescription
--nameTerm label (required)
--slugTerm slug (defaults to slugified name)
--parentParent term ID (for hierarchical taxonomies)

emdash menu

Manage navigation menus.

npx emdash menu list
npx emdash menu get primary

Returns the menu with all its items.

emdash site

Export a whole site to a .emdash site package, and import a package into an empty site. The site transfer guide explains what a package contains, what the target site needs, and how to read an import plan.

The token needs the admin scope, which the emdash login token has, or the matching transfer scopes: transfer:export to export, and transfer:analyze and transfer:execute to import. A token without them fails with INSUFFICIENT_SCOPE.

Progress messages always go to stderr, and the result goes to stdout. With --json, or when stdout is not a terminal, stdout contains only the JSON result. An error is written as { "error": { "code": "…", "message": "…" } }. The codes are the server’s error codes, plus INVALID_ARGUMENT for bad flags, PACKAGE_FILE_REQUIRED when a resumed import still needs the package file, and UNKNOWN_ERROR.

The commands retry network failures and 408, 429, and 5xx responses with backoff.

site export

Export the site and write it to a package file:

npx emdash site export --output site.emdash
OptionAliasDescriptionDefault
--output-oPackage file to write (required)
--no-commentsLeave comments and comment reactions outComments included

The command starts an export, advances it until it completes, and downloads the package file by file. It checks that the downloaded manifest matches the export’s package digest, and fails with TRANSFER_PACKAGE_DIGEST_MISMATCH before writing anything if it does not. It checks each file’s size and SHA-256 digest before writing it. The package is written to <output>.partial and renamed to the output path when it is complete.

The command keeps its progress in <output>.partial.json and the downloaded files in the <output>.parts/ directory. Run the same command again after an interruption to resume the same export; files already downloaded are checked and reused, and the command reports how many it reused. Both are deleted when the package is written. The progress file is ignored when it was written for another URL or another comments setting, or when its export failed or expired; the command then starts a new export.

The JSON result contains operationId, output, packageDigest, files, bytes, and resumed.

site import <file>

Import a package in two steps. Analyze it first, then confirm the plan digest that analysis printed:

npx emdash site import site.emdash --analyze
npx emdash site import site.emdash --plan sha256:3f1c… --confirm
OptionDescription
--analyzeUpload the package, analyze it, and print the import plan
--map-principal <from>=<to>With --analyze: map a package principal, by ID or email address, to a site user by ID or email address, or to none. Repeatable
--use-target-titleWith --analyze: keep this site’s title instead of the package’s
--use-target-taglineWith --analyze: keep this site’s tagline instead of the package’s
--plan <digest>The plan digest to execute, as sha256:<hex> or bare hex. Requires --confirm
--confirmExecute the plan given by --plan. Requires --plan
--yesAlias -y. With cancel or abandon: skip the confirmation prompt

--analyze verifies the whole package file locally, then finds the site’s existing import of the same package or creates one. It uploads the files the site does not have yet, runs analysis, and prints the plan: the package and plan digests, record counts, sizes, the title and tagline choice, each principal and its mapping, the transformations under “Differences from the source site”, the warnings, and the blockers. If an earlier import of the same package failed, was cancelled or abandoned, or expired, the command warns and starts a new import.

Decisions are stored with the import, so a later --analyze run without decision flags keeps them. Each change of decisions produces a new plan digest. Decisions cannot be combined with --plan, and --plan cannot be combined with --analyze.

--plan <digest> --confirm executes the import only when the digest matches the current plan, then advances it until it completes and prints the receipt. If the plan changed since you reviewed it, the command fails with TRANSFER_PLAN_DIGEST_MISMATCH; analyze again and confirm the new digest.

The JSON result of --analyze contains operationId, state, packageDigest, planDigest, executable, and the full plan. The JSON result of --confirm contains operationId, state (complete), receipt, and receiptDigestValid, which reports whether the receipt’s receiptDigest matches its contents.

These forms operate on an import by its operation ID:

CommandDescription
emdash site import status <operation-id>Print the import’s state, stage, progress, digests, and error, and how many files are uploaded. The JSON result is { operation, files: { declared, verified } }.
emdash site import resume <operation-id> [file]Continue the import from its current state: finish uploading, finish analysis and print the plan, or finish execution and print the receipt. Pass the package file only while the import is still uploading.
emdash site import receipt <operation-id>Print the receipt of a complete import, in the same shape as --confirm.
emdash site import cancel <operation-id>Cancel the import. A running import stops after its current batch; what it already wrote stays on the site.
emdash site import abandon <operation-id>Lift the write block that a failed or cancelled import leaves on the site. What the import wrote is not deleted, so reset the site or set up a new one before importing again.

cancel and abandon ask for confirmation. Pass --yes to skip the prompt; the prompt is also skipped with --json or when stdout is not a terminal. When stdin is not a terminal and neither applies, the command fails with INVALID_ARGUMENT. Declining the prompt changes nothing and exits with code 1. The JSON result of both is { operationId, state, operation }.

The import commands exit with these codes:

CodeMeaning
0Success. For status, an import that is in progress or complete
1An error, a declined prompt, an import that ended without a receipt, or a receipt whose digest does not match. For status, an import that failed, was cancelled or abandoned, or expired
2Analysis finished, but the plan has blockers

emdash plugin

Create, validate, bundle, and publish EmDash plugins. Marketplace login is separate from login to a CMS instance.

plugin init

Scaffold a sandboxed or native plugin:

npx emdash plugin init --dir ./my-plugin --name my-plugin --format sandboxed
OptionDescriptionDefault
--dirDirectory to createCurrent directory
--namePlugin package name or IDInteractive prompt
--formatsandboxed or nativeInteractive prompt
--nativeShortcut for --format nativefalse

plugin bundle

Validate a plugin and create its marketplace tarball:

npx emdash plugin bundle --dir ./my-plugin --outDir ./artifacts
OptionAliasDescriptionDefault
--dirPlugin directoryCurrent directory
--outDir-oTarball output directory./dist
--validateOnlyRun validation without creating a tarballfalse

plugin validate

Run the same validation as plugin bundle without creating a tarball:

npx emdash plugin validate --dir ./my-plugin

The optional --dir selects the plugin directory and defaults to the current directory.

plugin publish

Upload a bundle to the marketplace and, by default, wait for its processing result:

npx emdash plugin publish --tarball ./dist/my-plugin-1.0.0.tar.gz
OptionDescriptionDefault
--tarballExisting plugin tarball—
--dirPlugin directory used with --buildCurrent directory
--buildBuild the plugin before uploadfalse
--registryMarketplace base URLhttps://marketplace.emdashcms.com
--no-waitExit after upload without waiting for the processing resultfalse

Provide --tarball, or pass --build to build from --dir first.

plugin login

Authenticate to the marketplace through GitHub device flow. --registry selects a different marketplace and defaults to https://marketplace.emdashcms.com.

npx emdash plugin login

plugin logout

Remove the saved marketplace credential. The optional --registry must identify the same marketplace used for login.

npx emdash plugin logout

emdash export-seed

Export database schema and content as a seed file. Works directly on a local SQLite file.

The database must have every migration known to the installed EmDash version. If the command reports pending migrations, run npx emdash migrate, then export again. If the database was migrated by a newer EmDash version, upgrade the installed version before exporting. The export opens the database read-only and never applies migrations itself.

npx emdash export-seed [options] > seed.json

Options

OptionAliasDescriptionDefault
--database-dDatabase file path./data.db
--cwdWorking directoryCurrent directory
--with-contentInclude content (all or comma-separated collections)
--pretty / --no-prettyEnable or disable indented JSON outputPretty output enabled
--media-base-urlPublic URL of the site, used to write absolute $media URLs

Output format

The exported seed file includes:

  • Settings: Site title, tagline, social links
  • Collections: All collection definitions with fields
  • Block types: Every retained version and each type’s active version pointer
  • Taxonomies: Taxonomy definitions and terms
  • Menus: Navigation menus with items
  • Redirects: Redirect rules with status 301, 302, 307, or 308
  • Widget Areas: Widget areas and widgets
  • Sections: Reusable content blocks
  • Content (if requested): Entries with $media references and $ref: syntax for portability

Scheduled entries are exported as drafts, because a seed has no field for a publish time. The export leaves out, with a warning on stderr, anything emdash seed would reject: redirect rules with status 410 or 451, extra rules that share a source (possible in older databases), and sections whose slug contains characters other than lowercase letters, digits, and hyphens.

Media URLs

emdash seed downloads each $media URL and uploads the file to the target site’s storage, so it needs an absolute http or https URL it can reach. Pass the source site’s public URL to write absolute URLs:

npx emdash export-seed --with-content=all --media-base-url=https://example.com > seed.json

The site must serve its media from /_emdash/api/media/file/ under that URL while the seed is applied, and the URL must not point at localhost or a private network address, which emdash seed refuses to download from. Without --media-base-url, $media URLs are site-relative paths that emdash seed skips, leaving the fields empty, and the export prints a warning on stderr.

Image and file fields, and image sub-fields of repeaters, are exported as $media references. Images inside Portable Text fields keep their stored media ID and URL, which do not resolve on a different site.

emdash secrets

Generate and inspect the key used to encrypt plugin secrets.

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 your local .env file with --write. Wrangler and the Cloudflare Vite plugin read that file in local development. A standalone Node server does not load .env automatically; load it through the process manager or provide the key through the server’s process environment. The Node.js deployment guide shows the local command.

npx emdash secrets generate --write .env

--write refuses to overwrite an existing entry without --force. To rotate a deployment with existing encrypted data, prepend the generated key to the existing value and separate the keys with a comma. EmDash encrypts new values with the first key and uses older entries for decryption by kid. Re-save every plugin secret before removing an old key. EmDash does not currently list the key IDs still used by stored settings, so keep an inventory of the credentials you resave and verify each integration before removing its old key.

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

emdash auth (deprecated)

auth secret

Generate a legacy EMDASH_AUTH_SECRET value:

npx emdash auth secret

Existing installations can keep this variable to preserve stable commenter-IP hashes. It does not encrypt plugin secrets.

Generated files

emdash-env.d.ts

The Astro integration generates emdash-env.d.ts in the project root when the local development server starts. It refreshes the file after schema changes made through the running development site. The declarations augment EmDashCollections, so calls such as getEmDashCollection("posts") infer the fields defined in the local database.

This file is automatic and belongs to the local Astro development workflow. You do not need to run emdash types to create it.

.emdash/types.ts

The emdash types command fetches a running instance’s schema and writes standalone TypeScript interfaces. Use it when the schema lives on a remote EmDash instance, when tooling needs a file at a custom path, or when the local Astro development server is not running:

// Generated by EmDash CLI
// Do not edit manually - run `emdash types` to regenerate

import type { PortableTextBlock } from "emdash";

export interface Post {
	id: string;
	slug: string | null;
	status: string;
	title: string;
	content?: PortableTextBlock[];
	createdAt: Date;
	updatedAt: Date;
	publishedAt: Date | null;
	bylines?: ContentBylineCredit[];
	terms?: Record<string, TaxonomyTerm[]>;
}

The remote output contains standalone collection interfaces and does not augment EmDashCollections. It changes only when you run emdash types; emdash-env.d.ts uses module augmentation and refreshes as part of local development.

.emdash/schema.json

The command also writes a raw schema export named schema.json beside the selected TypeScript output. With the default output path, the file is .emdash/schema.json:

{
  "version": "a1b2c3d4",
  "collections": [
    {
      "slug": "posts",
      "label": "Posts",
      "fields": [...]
    }
  ]
}

Environment variables

VariableDescription
EMDASH_DATABASE_URLOverride database URL
EMDASH_TOKENAuth token for remote operations
EMDASH_URLDefault URL for commands using the shared remote client
EMDASH_HEADERSNewline-separated custom request headers for the shared remote client and login
EMDASH_ENCRYPTION_KEYKey for encrypting plugin secrets at rest. Operator-provided — never stored in the database. Generate with emdash secrets generate.
EMDASH_PREVIEW_SECRETOptional override for preview HMAC secret. When unset, EmDash generates and persists one in the options table.
EMDASH_IP_SALTOptional override for the commenter-IP hash salt. When unset, EmDash generates and persists one in the options table.
EMDASH_AUTH_SECRETLegacy. 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 common commands as package.json scripts for convenience:

{
	"scripts": {
		"dev": "astro dev",
		"types": "emdash types",
		"export-seed": "emdash export-seed",
		"db:reset": "rm -f data.db"
	}
}

General exit codes

Most commands use 0 for success and 1 for an error. emdash migrate also uses codes 2, 3, 4, and 130 for the specific outcomes listed in its exit-code table. emdash site import uses 2 when the import plan has blockers.

CodeDescription
0Success
1Error (configuration, network, database)