Scribe

Primeros pasos

Instala scribe-cms, define un esquema, escribe contenido y recupéralo totalmente tipado en cinco pasos.

View as Markdown

Instalación

pnpm add scribe-cms zod better-sqlite3

Requisitos: Node 20+ y Zod v4. Scribe no depende de ningún framework, por lo que funciona con cualquier entorno basado en Node. Dado que better-sqlite3 es un módulo nativo, debes mantenerlo fuera de tu empaquetador (consulta la página de la API de ejecución).

1. Crear scribe.config.ts

Colócalo en la raíz de tu proyecto:

import { z } from "zod";
import { defineConfig, defineContentType, field } from "scribe-cms";

const blogSchema = z.object({
  title: field.translatable(z.string().min(1)),
  description: field.translatable(z.string().min(50).max(250)),
  author: field.relation("author"),
  tags: field.structural(z.array(z.string()).default([])),
});

const authorSchema = z.object({
  name: field.structural(z.string().min(1)),
});

export default defineConfig({
  rootDir: ".", // relative to this file (CLI) / process.cwd() (runtime)
  locales: ["en", "fr", "de"],
  types: [
    defineContentType({
      id: "blog",
      path: "/blog/{slug}",
      schema: blogSchema,
      slugStrategy: "localized",
      orderBy: "-publishedAt",
    }),
    defineContentType({
      id: "author",
      contentDir: "authors",
      schema: authorSchema,
    }),
  ],
});

Las funciones defineConfig y defineContentType son funciones de identidad que conservan los tipos literales. Gracias a ellas, más adelante scribe.blog y related(doc, "author") estarán completamente tipados.

2. Escribir contenido

content/
  blog/
    hello-world.mdx
  authors/
    jane.mdx
---
title: "Hello, world"
description: "A first post that says hello to the world, at length, because the schema demands fifty characters."
author: jane
publishedAt: "2026-01-15"
---

The body is MDX. **Markdown** and components both work.

El nombre del archivo (hello-world) es el slug en inglés. El campo publishedAt viene integrado en todos los tipos (consulta la sección modelo de contenido).

3. Validar

Tras ejecutar pnpm install, la interfaz de línea de comandos scribe estará disponible en tu PATH (igual que ocurre con next):

pnpm scribe validate
pnpm scribe status

Intégralo al principio de tu proceso de compilación:

{
  "scripts": {
    "build": "scribe validate && <your framework build>"
  }
}

4. Leer contenido

import { createScribe } from "scribe-cms/runtime";
import config from "./scribe.config";

const scribe = createScribe(config);

const posts = scribe.blog.list(); // BlogDoc[], newest first
const { document } = scribe.blog.resolve("hello-world", "fr");
const author = scribe.blog.related(document!, "author"); // AuthorDoc, non-null

El tipado de document.frontmatter se obtiene directamente de tu esquema Zod. Consulta la API de ejecución para ver todos los detalles.

5. Traducir

export GEMINI_API_KEY=...   # or put it in .env
npx scribe translate --locale fr

Scribe busca todas las páginas que falten o estén desactualizadas en francés, traduce los campos marcados con field.translatable() y guarda el resultado en .scribe/store.sqlite. Debes hacer un commit de este directorio (nunca añadas .scribe/ a tu .gitignore). Tienes más detalles en la sección de traducción.