EmDash admite 17 tipos de campo para definir esquemas de contenido. Cada tipo se asigna a un tipo de columna SQLite y proporciona la IU de administración adecuada.
Resumen
La siguiente tabla enumera cada tipo de campo y su columna SQLite:
| Type | SQLite Column | Description |
|---|---|---|
string | TEXT | Entrada de texto corto |
text | TEXT | Texto multilínea |
url | TEXT | Valor URL |
number | REAL | Número decimal |
integer | INTEGER | Número entero |
boolean | INTEGER | Verdadero/falso |
datetime | TEXT | Fecha y hora |
select | TEXT | Elección única entre opciones |
multiSelect | JSON | Elecciones múltiples |
portableText | JSON | Contenido de texto enriquecido |
image | TEXT | Referencia de imagen |
file | TEXT | Referencia de archivo |
reference | none | Enlaza entradas de otra colección |
json | JSON | Datos JSON arbitrarios |
slug | TEXT | Identificador seguro para URL |
repeater | JSON | Grupo de campos repetible |
blocks | JSON | Composición de página tipada |
Tipos de texto
string
Texto corto de una sola línea. Úselo para títulos, nombres y valores breves.
{
slug: "title",
label: "Title",
type: "string",
required: true,
validation: {
minLength: 1,
maxLength: 200,
},
}
Opciones de validación:
minLength— Número mínimo de caracteresmaxLength— Número máximo de caracterespattern— Expresión regular que el valor debe cumplir
El editor limita la entrada a maxLength y muestra un contador de caracteres en vivo frente a las reglas de longitud.
Opciones del widget:
- Ninguna específica
text
Texto plano multilínea. Úselo para descripciones, extractos y texto plano más largo.
{
slug: "excerpt",
label: "Excerpt",
type: "text",
options: {
rows: 3,
},
}
Opciones de validación:
minLength— Número mínimo de caracteresmaxLength— Número máximo de caracterespattern— Expresión regular que el valor debe cumplir
El editor limita la entrada a maxLength y muestra un contador de caracteres en vivo frente a las reglas de longitud.
Opciones del widget:
rows— Número de filas en el textarea (predeterminado: 3)
url
Una dirección web. La API de contenido rechaza valores que no son URL válidas.
{
slug: "website",
label: "Website",
type: "url",
required: true,
}
Los campos URL se almacenan como texto. Use un campo string en su lugar cuando el valor pueda ser una ruta relativa como /about, porque las rutas relativas no son valores válidos para un campo url.
slug
Texto destinado a contener un valor similar a un slug. Este tipo de campo personalizado no genera ni sanea su valor.
{
slug: "legacy_slug",
label: "Legacy Slug",
type: "slug",
required: true,
unique: true,
}
Cada entrada de contenido ya tiene un slug de sistema reservado, que EmDash gestiona por separado para las URL públicas. Use un campo slug personalizado solo cuando el modelo de contenido necesite otro valor similar a un slug almacenado.
Tipos numéricos
number
Número decimal. Úselo para precios, valoraciones y medidas.
{
slug: "price",
label: "Price",
type: "number",
required: true,
validation: {
min: 0,
max: 999999.99,
},
}
Opciones de validación:
min— Valor mínimomax— Valor máximo
El editor establece min y max en la entrada numérica y muestra el rango permitido debajo.
Almacenado como SQLite REAL (punto flotante de 64 bits).
integer
Número entero. Úselo para cantidades, contadores y valores de orden.
{
slug: "quantity",
label: "Quantity",
type: "integer",
defaultValue: 1,
validation: {
min: 0,
max: 1000,
},
}
Opciones de validación:
min— Valor mínimomax— Valor máximo
El editor establece min y max en la entrada numérica y muestra el rango permitido debajo.
Almacenado como SQLite INTEGER.
boolean
Verdadero o falso. Úselo para interruptores y flags.
{
slug: "featured",
label: "Featured",
type: "boolean",
defaultValue: false,
}
Almacenado como SQLite INTEGER (0 o 1).
Fecha y hora
datetime
Un instante en el tiempo. Las escrituras de API, MCP y CLI deben incluir Z o un desplazamiento UTC explícito. La administración interpreta su selector de fecha y hora en la zona horaria configurada en Settings → General.
{
slug: "publishedAt",
label: "Published At",
type: "datetime",
}
Formato de almacenamiento: 2025-01-24T12:00:00.000Z
EmDash convierte la entrada aceptada a UTC con milisegundos de tres dígitos antes de almacenarla. Por ejemplo, 2025-01-24T21:00:00+09:00 se almacena como 2025-01-24T12:00:00.000Z. Use un campo string en su lugar cuando el valor sea una fecha de calendario o una hora local de reloj de pared en lugar de un instante.
Tipos de selección
select
Selección única entre opciones predefinidas.
{
slug: "status",
label: "Status",
type: "select",
required: true,
defaultValue: "draft",
validation: {
options: ["draft", "published", "archived"],
},
}
Opciones de validación:
options— Array opcional de valores permitidos. Proporciónelo para presentar opciones predefinidas y rechazar otras cadenas; sin él, la validación acepta cualquier cadena.
Almacenado como TEXT que contiene el valor seleccionado.
multiSelect
Selecciones múltiples entre opciones predefinidas.
{
slug: "tags",
label: "Tags",
type: "multiSelect",
validation: {
options: ["news", "tutorial", "review", "opinion"],
},
}
Opciones de validación:
options— Array opcional de valores permitidos. Proporciónelo para presentar opciones predefinidas y rechazar otras cadenas; sin él, la validación acepta cualquier array de cadenas.
Almacenado como array JSON: ["news", "tutorial"]
Contenido enriquecido
portableText
Contenido de texto enriquecido en formato Portable Text. Admite encabezados, listas, enlaces, imágenes y bloques personalizados.
{
slug: "content",
label: "Content",
type: "portableText",
required: true,
}
El valor se almacena como un array JSON de bloques Portable Text, por ejemplo:
[
{
"_type": "block",
"style": "normal",
"children": [{ "_type": "span", "text": "Hello world" }]
}
]
Los plugins pueden añadir tipos de bloque personalizados (embeds, widgets, etc.) al editor. Aparecen en el menú de comandos slash. Renderizar el bloque guardado en el sitio público requiere un componente Astro de un plugin nativo o paquete companion. Consulte Componentes de renderizado de Portable Text.
Tipos de medios
image
Referencia a una imagen subida. Incluye metadatos como dimensiones y texto alternativo.
{
slug: "featuredImage",
label: "Featured Image",
type: "image",
validation: {
allowedMimeTypes: ["image/jpeg", "image/png"],
},
options: {
darkVariant: true,
},
}
Opciones del widget:
darkVariant— Ofrece a los editores un segundo espacio para una imagen mostrada en esquemas de color oscuros (predeterminado: false). Consulte Dark Mode.
Opciones de validación:
allowedMimeTypes— Lista no vacía de tipos MIME exactos aceptados para el medio seleccionado
El valor se almacena como un objeto con la referencia de medios y sus metadatos:
{
"id": "01HXK5MZSN...",
"src": "/_emdash/api/media/file/01HXK5MZSN...",
"alt": "Description",
"width": 1920,
"height": 1080,
"provider": "local",
"meta": {
"storageKey": "01HXK5MZSN....jpg"
}
}
Con darkVariant habilitado, el valor puede llevar la contraparte oscura bajo darkVariant, con la misma forma:
{
"id": "01HXK5MZSN...",
"alt": "Architecture diagram",
"width": 1920,
"height": 1080,
"darkVariant": {
"id": "01HXK5N2QT...",
"width": 1920,
"height": 1080
}
}
file
Referencia a un archivo subido como un documento o PDF.
{
slug: "document",
label: "Document",
type: "file",
validation: {
allowedMimeTypes: ["application/pdf"],
},
}
Opciones de validación:
allowedMimeTypes— Lista no vacía de tipos MIME exactos aceptados para el medio seleccionado
El valor se almacena como una referencia de proveedor con metadatos en caché:
{
"id": "01HXK5MZSN...",
"provider": "local",
"filename": "report.pdf",
"mimeType": "application/pdf",
"meta": {
"storageKey": "01HXK5MZSN....pdf"
}
}
url y size, como los demás campos de metadatos en caché, son opcionales. Las consultas de contenido devuelven el
valor persistido tal cual y no lo hidratan desde la biblioteca de medios. Consulte
Valores de archivo y metadatos actuales para las
APIs de consulta canónicas cuando necesite metadatos frescos o una URL específica del proveedor.
Tipos relacionales
reference
Enlaza una entrada con entradas de otra colección y se muestra como un selector de entradas en la administración. Sus enlaces pertenecen a una relación: un objeto de esquema que une dos colecciones, nombra cada lado y limita cuántas entradas puede enlazar cada lado. Relations cubre el flujo de trabajo del editor y la administración.
El siguiente campo enlaza una publicación con una entrada de la colección authors:
{
slug: "author",
label: "Author",
type: "reference",
required: true,
validation: {
targetCollection: "authors",
multiple: false,
},
}
Validación:
targetCollection— Slug de la colección a la que enlaza este campo. Crear el campo crea una relación para él.multiple— Permitir más de una entrada enlazada (predeterminado: false). Léalo solo junto contargetCollection, porque el límite pertenece entonces a la nueva relación.relation— Slug de una relación existente a la que vincularse en lugar de crear una.relationSide— En qué extremo derelationse sitúa esta colección,"parent"o"child". Establézcalo solo para una relación cuyos dos extremos sean la misma colección, donde ambos extremos coinciden.
Indique targetCollection o relation. Un campo creado desde targetCollection se convierte en el
extremo padre de una relación llamada {collection}_{field}, cuyo lado hijo toma la etiqueta del campo y
mantiene una entrada a menos que se establezca multiple. Un campo creado desde relation ve esa relación desde
el extremo en el que se sitúa su colección, y la colección del otro extremo es el destino del campo. Una
relación acepta un campo por extremo, por lo que se rechaza un segundo campo sobre el mismo extremo. Ambas formas
almacenan relation, relationSide y targetCollection en el campo creado, y la colección
destino queda fija a partir de entonces: para cambiarla, elimine el campo y añada uno nuevo. Renombrar el
campo renombra el lado de la relación que ve.
Un campo de referencia no añade ninguna columna a la tabla de la colección. Sus enlaces viven en
_emdash_content_references, indexados por el grupo de traducción de cada entrada, de modo que una selección se comparte
entre las traducciones de una entrada en lugar de establecerse por locale. Las lecturas de contenido devuelven las entradas enlazadas
bajo references, indexadas por el slug del campo, en lugar de en data. En una plantilla, pida el campo por
nombre — consulte Leer campos de referencia.
Un campo vinculado a una relación no puede establecer indexed, porque no almacena ninguna columna que indexar, y la búsqueda
del sitio no lo cubre.
Campos sin relación
Un campo de referencia que no nombra ni una relación ni una colección destino conserva una columna TEXT y
guarda en ella un ID de entrada:
"01HXK5MZSN..."
Un campo cuyo options.allowMultiple está establecido guarda un array JSON de IDs de entrada en la misma columna:
["01HXK5MZSN...", "01HXK6NATS..."]
La columna se lee y escribe como cualquier otra columna de texto, el esquema de la colección valida el
valor como cadena, y el campo puede establecer indexed y actuar como filtro de lista de contenido. Se muestra como un
cuadro de texto en lugar de un selector.
Para convertirlo en un selector, abra el campo en Content Types y elija una colección referenciada.
EmDash crea la relación, copia los IDs de entrada de la columna como enlaces y borra los flags
searchable e indexed del campo, de modo que los filtros de lista de contenido y la búsqueda del sitio dejan de cubrirlo. La
columna permanece en su lugar y deja de escribirse. Relations
cubre el mismo paso desde el lado del editor.
Un sitio actualizado desde una versión anterior puede conservar campos en este estado. Consulte Los campos de referencia se vinculan a relaciones para lo que la actualización vincula y lo que deja para que usted vincule.
Tipos flexibles
json
Datos JSON arbitrarios. Úselo para estructuras anidadas complejas, integraciones de terceros o datos sin un esquema fijo.
{
slug: "metadata",
label: "Metadata",
type: "json",
}
Almacenado tal cual en una columna JSON de SQLite.
repeater
Una lista repetible de filas estructuradas. Defina al menos un subcampo en validation.subFields; los editores pueden entonces añadir, eliminar, reordenar y editar filas sin introducir JSON en bruto.
El siguiente campo almacena una lista de especificaciones de producto:
{
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" },
],
},
}
Los valores de repeater se almacenan como un array de objetos:
[
{
"label": "Weight",
"value": "1.2 kg",
"source": "https://example.com/specifications"
}
]
Los tipos de subcampo permitidos son string, text, url, number, integer, boolean, datetime, select e image. Los repeaters no pueden contener otro repeater ni un campo complejo como portableText, reference o file.
La validación de repeater acepta estas propiedades:
subFields— Una o más definiciones de subcampo. Cada definición requiereslug,labelytype; también puede establecerrequired. Un subcamposelectsuministra sus opciones medianteoptions.minItems— Número mínimo de filas. Debe ser cero o mayor.maxItems— Número máximo de filas. Debe ser uno o mayor y no puede ser menor queminItems.
blocks
Una lista ordenada de bloques de contenido tipados. Cada tipo de bloque tiene sus propios campos y conserva versiones numeradas. Defina los tipos de bloque mediante la API de esquema, MCP o un archivo seed antes de añadirlos a un campo de colección.
El siguiente campo permite a los editores componer una página a partir de bloques hero y call-to-action:
{
slug: "layout",
label: "Layout",
type: "blocks",
validation: {
allowedTypes: ["hero", "call_to_action"],
maxItems: 20,
},
}
Cada bloque almacenado lleva su tipo, versión y clave estable junto a los campos declarados por esa versión:
[
{
"_type": "hero",
"_version": 1,
"_key": "01K5AB3F7M9QZ2X8W4V6T1R0YH",
"heading": "Bread made slowly, by hand."
}
]
La validación de blocks acepta estas propiedades:
allowedTypes— Slugs de tipos de bloque ordenados disponibles para bloques nuevos.retiredTypes— Tipos de bloque gestionados por el servidor retenidos para el contenido almacenado pero no disponibles para bloques nuevos.minItems— Número mínimo de bloques. Elevarlo por encima de cero en una colección poblada requiere una migración de contenido.maxItems— Número máximo de bloques, hasta 100.
Un campo blocks es opcional y por defecto es un array vacío. No puede ser required, unique, searchable, indexed ni renderizado por un widget de campo personalizado. Las definiciones de bloque pueden usar campos escalares, de texto, de selección, Portable Text, imagen, archivo y repeater. No pueden contener referencias, JSON, slugs ni blocks anidados.
Renderice el array almacenado con <Blocks value components fallback> de emdash/ui. Consulte Crear páginas con blocks para ejemplos de seed, mapa de componentes, renderer ausente, activación y migración.
Propiedades de campo
Todos los campos admiten estas propiedades comunes:
| Property | Type | Description |
|---|---|---|
slug | string | Identificador único (obligatorio) |
label | string | Nombre para mostrar (obligatorio) |
type | FieldType | Tipo de campo (obligatorio) |
required | boolean | Exigir un valor (predeterminado: false) |
unique | boolean | Exigir unicidad (predeterminado: false) |
searchable | boolean | Incluir el campo en la búsqueda de texto completo (predeterminado: false) |
indexed | boolean | Habilitar ordenación/filtrado indexado |
translatable | boolean | Almacenar un valor por locale (predeterminado: true) |
defaultValue | unknown | Valor predeterminado para entradas nuevas |
validation | object | Reglas de validación específicas del tipo |
widget | string | Anulación de widget personalizado |
options | object | Configuración del widget |
sortOrder | number | Orden de visualización en la administración |
indexed está disponible para campos escalares: string, url, number, integer, boolean,
datetime, select, reference y slug. Un campo indexado puede pasarse como el campo orderBy
o usarse en fieldFilters en las consultas de lista de contenido. Evite indexar campos que no se usan
para ordenar o filtrar porque cada índice añade sobrecarga de almacenamiento y escritura.
searchable añade el texto del campo al índice de búsqueda de texto completo de la colección. Establezca translatable: false para identificadores, precios, flags y otros valores que deben permanecer iguales en todas las traducciones de una entrada; cuando un locale cambia un campo no traducible, EmDash sincroniza el valor con sus entradas traducidas.
El tipo blocks usa solo slug, label, type, translatable, validation y sortOrder de este conjunto común. Su array nunca es obligatorio a nivel de columna y siempre tiene como valor predeterminado [].
Slugs de campo reservados
Estos slugs están reservados y no pueden usarse:
idslugstatusauthor_idprimary_byline_idcreated_atupdated_atpublished_atscheduled_atdeleted_atversionlive_revision_iddraft_revision_idtermsbylinesbyline
Tipos TypeScript
Importe las definiciones de tipos de campo para uso programático:
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",
"blocks",
];