EmDash supports 16 field types for defining content schemas. Each type maps to a SQLite column type and provides appropriate admin UI.
Overview
The following table lists every field type and its SQLite column:
| Type | SQLite Column | Description |
|---|---|---|
string | TEXT | Short text input |
text | TEXT | Multi-line text |
url | TEXT | URL value |
number | REAL | Decimal number |
integer | INTEGER | Whole number |
boolean | INTEGER | True/false |
datetime | TEXT | Date and time |
select | TEXT | Single choice from options |
multiSelect | JSON | Multiple choices |
portableText | JSON | Rich text content |
image | TEXT | Image reference |
file | TEXT | File reference |
reference | TEXT | Reference to another entry |
json | JSON | Arbitrary JSON data |
slug | TEXT | URL-safe identifier |
repeater | JSON | Repeating group of fields |
Text types
string
Short, single-line text. Use for titles, names, and short values.
{
slug: "title",
label: "Title",
type: "string",
required: true,
validation: {
minLength: 1,
maxLength: 200,
},
}
Validation options:
minLength— Minimum character countmaxLength— Maximum character countpattern— Regular expression the value must match
Widget options:
- None specific
text
Multi-line plain text. Use for descriptions, excerpts, and longer plain text.
{
slug: "excerpt",
label: "Excerpt",
type: "text",
options: {
rows: 3,
},
}
Validation options:
minLength— Minimum character countmaxLength— Maximum character countpattern— Regular expression the value must match
Widget options:
rows— Number of rows in textarea (default: 3)
url
A web address. The content API rejects values that are not valid URLs.
{
slug: "website",
label: "Website",
type: "url",
required: true,
}
URL fields are stored as text. Use a string field instead when a value may be a relative path such as /about, because relative paths are not valid values for a url field.
slug
Text intended to hold a slug-like value. This custom field type does not generate or sanitize its value.
{
slug: "legacy_slug",
label: "Legacy Slug",
type: "slug",
required: true,
unique: true,
}
Every content entry already has a reserved system slug, which EmDash manages separately for public URLs. Use a custom slug field only when the content model needs another stored slug-like value.
Number types
number
Decimal number. Use for prices, ratings, and measurements.
{
slug: "price",
label: "Price",
type: "number",
required: true,
validation: {
min: 0,
max: 999999.99,
},
}
Validation options:
min— Minimum valuemax— Maximum value
Stored as SQLite REAL (64-bit floating point).
integer
Whole number. Use for quantities, counts, and order values.
{
slug: "quantity",
label: "Quantity",
type: "integer",
defaultValue: 1,
validation: {
min: 0,
max: 1000,
},
}
Validation options:
min— Minimum valuemax— Maximum value
Stored as SQLite INTEGER.
boolean
True or false. Use for toggles and flags.
{
slug: "featured",
label: "Featured",
type: "boolean",
defaultValue: false,
}
Stored as SQLite INTEGER (0 or 1).
Date and time
datetime
Date and time value. Stored in ISO 8601 format.
{
slug: "publishedAt",
label: "Published At",
type: "datetime",
}
Storage format: 2025-01-24T12:00:00.000Z
Selection types
select
Single selection from predefined options.
{
slug: "status",
label: "Status",
type: "select",
required: true,
defaultValue: "draft",
validation: {
options: ["draft", "published", "archived"],
},
}
Validation options:
options— Optional array of allowed values. Provide it to present predefined choices and reject other strings; without it, validation accepts any string.
Stored as TEXT containing the selected value.
multiSelect
Multiple selections from predefined options.
{
slug: "tags",
label: "Tags",
type: "multiSelect",
validation: {
options: ["news", "tutorial", "review", "opinion"],
},
}
Validation options:
options— Optional array of allowed values. Provide it to present predefined choices and reject other strings; without it, validation accepts any string array.
Stored as JSON array: ["news", "tutorial"]
Rich content
portableText
Rich text content using Portable Text format. Supports headings, lists, links, images, and custom blocks.
{
slug: "content",
label: "Content",
type: "portableText",
required: true,
}
The value is stored as a JSON array of Portable Text blocks, for example:
[
{
"_type": "block",
"style": "normal",
"children": [{ "_type": "span", "text": "Hello world" }]
}
]
Plugins can add custom block types (embeds, widgets, etc.) to the editor. These appear in the slash command menu. Rendering the saved block on the public site requires an Astro component from a native plugin or companion package. See Portable Text rendering components.
Media types
image
Reference to an uploaded image. Includes metadata like dimensions and alt text.
{
slug: "featuredImage",
label: "Featured Image",
type: "image",
validation: {
allowedMimeTypes: ["image/jpeg", "image/png"],
},
options: {
darkVariant: true,
},
}
Widget options:
darkVariant— Offer editors a second slot for an image shown in dark color schemes (default: false). See Dark Mode.
Validation options:
allowedMimeTypes— Non-empty list of exact MIME types accepted for the selected media
The value is stored as an object with the media reference and its metadata:
{
"id": "01HXK5MZSN...",
"src": "/_emdash/api/media/file/01HXK5MZSN...",
"alt": "Description",
"width": 1920,
"height": 1080,
"provider": "local",
"meta": {
"storageKey": "01HXK5MZSN....jpg"
}
}
With darkVariant enabled, the value can carry the dark counterpart under darkVariant, in the same shape:
{
"id": "01HXK5MZSN...",
"alt": "Architecture diagram",
"width": 1920,
"height": 1080,
"darkVariant": {
"id": "01HXK5N2QT...",
"width": 1920,
"height": 1080
}
}
file
Reference to an uploaded file such as a document or PDF.
{
slug: "document",
label: "Document",
type: "file",
validation: {
allowedMimeTypes: ["application/pdf"],
},
}
Validation options:
allowedMimeTypes— Non-empty list of exact MIME types accepted for the selected media
The value is stored as a provider reference with cached metadata:
{
"id": "01HXK5MZSN...",
"provider": "local",
"filename": "report.pdf",
"mimeType": "application/pdf",
"meta": {
"storageKey": "01HXK5MZSN....pdf"
}
}
url and size, like the other cached metadata fields, are optional. Content queries return the
persisted value as-is and do not hydrate it from the media library. See
File values and current metadata for the
canonical lookup APIs when you need fresh metadata or a provider-specific URL.
Relational types
reference
Reference to another content entry.
{
slug: "author",
label: "Author",
type: "reference",
required: true,
options: {
collection: "authors",
},
}
Widget options:
collection— Target collection slug (required)
A reference is stored as the target entry ID:
"01HXK5MZSN..."
Flexible types
json
Arbitrary JSON data. Use for complex nested structures, third-party integrations, or data without a fixed schema.
{
slug: "metadata",
label: "Metadata",
type: "json",
}
Stored as-is in SQLite JSON column.
repeater
A repeating list of structured rows. Define at least one sub-field in validation.subFields; editors can then add, remove, reorder, and edit rows without entering raw JSON.
The following field stores a list of product specifications:
{
slug: "specifications",
label: "Specifications",
type: "repeater",
validation: {
minItems: 1,
maxItems: 12,
subFields: [
{ slug: "label", label: "Label", type: "string", required: true },
{ slug: "value", label: "Value", type: "text", required: true },
{ slug: "source", label: "Source", type: "url" },
],
},
}
Repeater values are stored as an array of objects:
[
{
"label": "Weight",
"value": "1.2 kg",
"source": "https://example.com/specifications"
}
]
The allowed sub-field types are string, text, url, number, integer, boolean, datetime, select, and image. Repeaters cannot contain another repeater or a complex field such as portableText, reference, or file.
Repeater validation accepts these properties:
subFields— One or more sub-field definitions. Each definition requiresslug,label, andtype; it can also setrequired. Aselectsub-field supplies its choices throughoptions.minItems— Minimum number of rows. Must be zero or greater.maxItems— Maximum number of rows. Must be one or greater and cannot be less thanminItems.
Field properties
All fields support these common properties:
| Property | Type | Description |
|---|---|---|
slug | string | Unique identifier (required) |
label | string | Display name (required) |
type | FieldType | Field type (required) |
required | boolean | Require a value (default: false) |
unique | boolean | Enforce uniqueness (default: false) |
searchable | boolean | Include the field in full-text search (default: false) |
indexed | boolean | Enable indexed field sorting/filtering |
translatable | boolean | Store a value per locale (default: true) |
defaultValue | unknown | Default value for new entries |
validation | object | Type-specific validation rules |
widget | string | Custom widget override |
options | object | Widget configuration |
sortOrder | number | Display order in admin |
indexed is available for scalar fields: string, url, number, integer, boolean,
datetime, select, reference, and slug. An indexed field can be passed as the orderBy
field or used in fieldFilters in content list queries. Avoid indexing fields that are not used
for sorting or filtering because every index adds storage and write overhead.
searchable adds the field’s text to the collection’s full-text search index. Set translatable: false for identifiers, prices, flags, and other values that must stay the same across every translation of an entry; when one locale changes a non-translatable field, EmDash synchronizes the value to its translated entries.
Reserved field slugs
These slugs are reserved and cannot be used:
idslugstatusauthor_idprimary_byline_idcreated_atupdated_atpublished_atscheduled_atdeleted_atversionlive_revision_iddraft_revision_idtermsbylinesbyline
TypeScript types
Import the field type definitions for programmatic use:
import type { FieldType, Field, CreateFieldInput } from "emdash";
const fieldTypes: FieldType[] = [
"string",
"text",
"url",
"number",
"integer",
"boolean",
"datetime",
"select",
"multiSelect",
"portableText",
"image",
"file",
"reference",
"json",
"slug",
"repeater",
];