How to Add Custom Fields in EmDash CMS

Adding a custom field to a collection you've already got content in is one of the more common day-two EmDash tasks — a new "featured" toggle, an SEO override field, a rating. This covers the three ways to do it and what actually happens underneath.
Table of Contents
- What Actually Happens When You Add a Field
- Option 1: The Admin UI
- Option 2: The CLI
- Option 3: The REST API Directly
- Choosing the Right Field Type
- Reserved Field Slugs You Can't Use
- Removing a Field (And Why It's Irreversible)
- Frequently Asked Questions
- Can I change a field's type after content already exists?
- Will a non-technical editor accidentally break the schema?
- Does adding a field require a redeploy?
- How do I see what fields a collection already has before adding more?
- The Bottom Line
What Actually Happens When You Add a Field
Adding a field through the admin UI runs three steps: insert a record into _emdash_fields, run ALTER TABLE ec_<collection> ADD COLUMN <name> <TYPE>, and regenerate the Zod schema used for validation.
That's a real, live schema change to a real database column — not a JSON blob getting a new key. It's also why field types map to specific SQLite column types (TEXT, REAL, INTEGER, JSON), and why the operation is instant: SQLite supports adding a column at runtime with no migration downtime, and existing rows simply get `NULL` (or the field's `defaultValue`) for the new column.
Option 1: The Admin UI
- Go to Content Types (the schema builder) in the admin panel.
- Open the collection you want to add a field to.
- Add a field, choose its type, and set validation/options as needed.
- Save — the field is live immediately, and existing content editors will see it on their next visit to that collection.
Option 2: The CLI
npx emdash schema add-field posts featured --type boolean --required
npx emdash schema add-field posts subtitle --type string --label "Subtitle"
npx emdash schema add-field posts body --type portableText --label "Body Content"Useful for scripting a repeatable setup, or for changing a deployed site's schema from your machine without opening the admin UI — the CLI's `schema` commands talk to the same REST API a running instance exposes, so they work identically against local dev or a live deployment (pass `--url` to target a deployed site).
Option 3: The REST API Directly
POST /_emdash/api/schema/collections/posts/fields
Content-Type: application/json
{
"slug": "rating",
"label": "Rating",
"type": "number",
"required": false,
"validation": { "min": 1, "max": 5 }
}The full set of field-management endpoints, for reference:
GET /_emdash/api/schema/collections/:slug/fields
POST /_emdash/api/schema/collections/:slug/fields
PUT /_emdash/api/schema/collections/:collectionSlug/fields/:fieldSlug
DELETE /_emdash/api/schema/collections/:collectionSlug/fields/:fieldSlug
POST /_emdash/api/schema/collections/:slug/fields/reorderThe reorder endpoint takes a full ordered array of field slugs — useful for cleaning up a collection's admin editor layout after several fields have been bolted on over time in a less-than-ideal order:
{ "fieldSlugs": ["title", "content", "author", "publishedAt"] }Choosing the Right Field Type
A quick decision guide for the most common "which type do I actually want" questions:
- A short label or name → string, not text.
- A paragraph of plain description → text.
- Rich formatted content with headings/links/images → portableText.
- A yes/no toggle → boolean, not select with two options.
- A fixed set of choices, pick one → select.
- A fixed set of choices, pick several → multiSelect.
- Linking to another collection's entry → reference (add allowMultiple: true in options for a many-relationship).
- Genuinely unstructured, dynamic data → json, used sparingly since it has no validation.
Reserved Field Slugs You Can't Use
A specific, easy-to-hit error: certain slugs are reserved by EmDash's own system columns and will be rejected if you try to add a field with that exact name:
- id, slug, status, author_id, primary_byline_id
- created_at, updated_at, published_at, scheduled_at, deleted_at
- version, live_revision_id, draft_revision_id
- terms, bylines, byline
If you're porting a field from another platform that happens to use one of these names (a WordPress custom field literally named "status", for instance), rename it — `content_status` or similar — rather than fighting the collision.
Removing a Field (And Why It's Irreversible)
npx emdash schema remove-field posts legacy_fieldRemoving a field deletes its column and data. Test schema changes against a preview environment before running them against production.
There's no undo — the column and every value it held are gone. If there's any chance you'll want that data back, export a backup (`npx emdash export-seed --with-content posts`) before removing the field, not after.
Frequently Asked Questions
Can I change a field's type after content already exists?
Yes, though EmDash rebuilds the underlying table to do it (create a new table, copy rows, drop the old one, rename) since SQLite doesn't support changing a column's type in place. Review existing values first — a type change that can't cleanly convert existing data (free text into a strict `select` list, for instance) can produce validation conflicts.
Will a non-technical editor accidentally break the schema?
Only Admin-role users can create, modify, or delete collections and fields — Editor and below can use existing fields but can't change the schema itself, so a content editor with a lower role literally can't perform this operation by accident.
Does adding a field require a redeploy?
No — it's a live database change, effective immediately in the admin panel and in any query that reads the collection. No rebuild or redeploy needed, the same "instant" property that applies to content edits.
How do I see what fields a collection already has before adding more?
`npx emdash schema get posts`, or `GET /_emdash/api/schema/collections/posts?includeFields=true` — both return the current, live field list rather than relying on memory or stale documentation.
The Bottom Line
Adding a field to an existing EmDash collection is a real, instant, live schema change — three equivalent ways to do it (admin UI, CLI, REST API) depending on whether you want a form, a script, or programmatic control. Watch for the reserved-slug list, and back up before removing a field, since that specific operation has no undo. See our broader guide to customizing content models for building a whole new collection from scratch.




Comments