Scribe

Modelo de contenido

Archivos, frontmatter, campos integrados, redirecciones y lo que verifica scribe validate.

View as Markdown

Archivos

Un documento equivale a un archivo .mdx (o .md) en la carpeta del tipo:

content/
  blog/
    hello-world.mdx        → slug "hello-world"
    _redirects.json        → reglas de redirección para este tipo (opcional)
  authors/
    jane.mdx               → slug "jane"
  • El nombre del archivo es el slug en inglés. Los slugs van en minúsculas y usan kebab-case.
  • En el disco solo existen los archivos en inglés; las versiones localizadas se guardan en la base de datos SQLite.
  • Los archivos cuyo nombre empieza por _ o mayúscula (por ejemplo, PUBLISHING.md) se ignoran, lo que te permite guardar notas junto a tu contenido.

Frontmatter

El frontmatter usa YAML y se valida mediante el esquema de Zod del tipo:

---
title: "Hello, world"
description: "Una descripción lo suficientemente larga para el esquema."
author: jane
publishedAt: "2026-01-15"
updatedAt: "2026-02-01"
---

Body is MDX.

La validación se rige por tu esquema de Zod. Si usas un z.object normal, las claves desconocidas se eliminan en silencio; usa .strict() si prefieres que los errores tipográficos en los nombres de los campos detengan la validación.

Campos integrados

Estos campos están disponibles en todos los tipos de contenido sin necesidad de declararlos en el esquema. Se extraen del frontmatter antes de ejecutar tu esquema, por lo que declararlos en Zod no tiene ningún efecto:

CampoTipoDescripción
publishedAtFecha ISOFecha de publicación.
updatedAtFecha ISOÚltima actualización importante. Por defecto es publishedAt. Controla el lastModified del sitemap.
noindexbooleanExcluye el documento del sitemap. Puedes exponerlo como etiqueta meta robots en tus páginas.
canonicalPathstringSobrescribe manualmente la ruta de la URL canónica.

Los documentos localizados heredan publishedAt, updatedAt, noindex y canonicalPath del documento original en inglés. Los traductores no pueden modificarlos.

Todo documento cargado incluye también slug, enSlug (el slug original en inglés, que equivale a slug en los documentos en dicho idioma), locale, frontmatter y content.

Tipos sin cuerpo

Las colecciones que solo sirven como referencia (un tipo model o category cuyo esquema es totalmente estructural) no suelen tener cuerpo MDX. Para hacerlo explícito, declara body: false en el tipo:

defineContentType({
  id: "model",
  contentDir: "models",
  schema: modelSchema,
  body: false, // las entradas solo tienen frontmatter
});

El valor por defecto es body: true, lo que garantiza la compatibilidad con versiones anteriores. En un tipo body: false, cualquier contenido en el cuerpo que no sea espacio en blanco generará un error de validación, el cargador omitirá el análisis MDX y las exportaciones estáticas no incluirán cuerpo. Un tipo sin cuerpo y con cero campos traducibles queda excluido de todos los flujos de traducción (evitando avisos innecesarios de contenido faltante u obsoleto). Si el tipo sin cuerpo conserva algún campo traducible, se mantendrá en las tareas pendientes con una carga que solo incluirá el frontmatter. Consulta la sección de traducción para ver las reglas sobre qué es traducible.

Más allá del frontmatter

Los cuerpos MDX permiten hacer más que escribir texto simple:

  • Los tokens integrados insertan enlaces, URLs de recursos y literales no traducibles directamente en el cuerpo, resolviéndose por idioma en el momento de lectura.
  • Los recursos declarados con field.asset() se validan en el disco y se convierten en URLs públicas al cargar.

Redirecciones: _redirects.json

Puedes añadir un archivo _redirects.json opcional en cada carpeta de tipo de contenido para declarar migraciones de slugs y documentos retirados. Las redirecciones siguen funcionando aunque elimines el archivo MDX original. Los slugs traducidos de origen se expanden automáticamente desde SQLite.

{
  "redirects": [
    { "from": "hello-world", "toSlug": "hello-scribe" },
    { "from": ["old-a", "old-b"], "toSlug": "hello-scribe" },
    { "from": "moved-post", "toType": "glossary", "toSlug": "virtual-try-on" },
    { "from": "retired-page", "toUrl": "/pricing" },
    { "from": "retired-ext", "toUrl": "https://example.com/app" }
  ]
}

Existen tres tipos de redirecciones (solo puede haber un destino por entrada):

TipoCamposDescripción
Mismo tipotoSlugSlug en inglés de destino dentro del mismo tipo de contenido. La URL se crea a partir del path del tipo y se localiza por idioma.
Otro tipotoType + toSlugSlug en inglés de destino en otro tipo de contenido enrutable (debe tener un path).
Cualquier destinotoUrlRuta relativa a la raíz del mismo sitio o URL externa absoluta, idéntica para todos los idiomas.
  • from: Solo admite slugs en inglés. Los slugs traducidos de origen se resuelven desde SQLite.
  • permanent es opcional (su valor por defecto es true).

Para retirar o renombrar un documento, añade una entrada a _redirects.json, elimina (o renombra) el archivo MDX original, ejecuta scribe validate y vuelve a compilar. La función buildAllContentRedirects() genera las reglas de redirección para la configuración de tu proxy o framework.

Validación

scribe validate

Verifica, por cada archivo en inglés, la estructura del esquema, las formas de los campos integrados, tu hook crossValidate y la compilación MDX del cuerpo. Si un cuerpo no se puede procesar como MDX, se produce un error que bloquea la compilación. Esto aplica tanto a los textos originales en inglés como a las traducciones guardadas.

A nivel de proyecto, también verifica la integridad de las relaciones (una relación requerida huérfana genera un error, mientras que una opcional genera una advertencia), las reglas de _redirects.json (destinos válidos, ausencia de orígenes duplicados y sin cadenas de redirección), las reglas de sufijos para slugs localizados, los campos de recursos declarados (existencia de archivos, formats, maxKB), los tokens integrados en el cuerpo (etiquetas mal formadas, relaciones huérfanas, enlaces :href a tipos no enrutables, claves vars faltantes, archivos de recursos faltantes), los tipos body: false que incluyen contenido en el cuerpo, los recursos de imagen que faltan si se ha configurado el directorio de recursos y la existencia de la base de datos de traducciones.

El código de salida es distinto de cero si se detecta algún error. Ejecútalo antes de iniciar tu proceso de compilación:

{
  "scripts": {
    "build": "scribe validate && <tu proceso de compilación>"
  }
}
Modelo de contenido · Scribe