---
order: 1
section: start
title: Erste Schritte
description: >-
  Installiere scribe-cms, definiere ein Schema, verfasse Inhalte und lies sie in
  fünf einfachen Schritten wieder typsicher aus.
noindex: false
canonicalPath: /de/docs/getting-started
---
## Installieren

```bash
pnpm add scribe-cms zod better-sqlite3
```

Voraussetzungen: Node 20+, Zod v4. Scribe ist framework-unabhängig und funktioniert mit jedem Node-basierten Stack. `better-sqlite3` ist ein natives Modul und sollte in deinem Bundler als extern konfiguriert werden (siehe Seite [Runtime API](/docs/runtime-api)).

## 1. `scribe.config.ts` erstellen

Lege die Datei im Root-Verzeichnis deines Projekts ab:

```ts
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: ".", // relativ zu dieser Datei (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,
    }),
  ],
});
```

`defineConfig` und `defineContentType` sind Identitätsfunktionen, die literale Typen erhalten. Sie sorgen dafür, dass später Aufrufe wie `scribe.blog` und `related(doc, "author")` vollständig typsicher sind.

## 2. Inhalte schreiben

```text
content/
  blog/
    hello-world.mdx
  authors/
    jane.mdx
```

```mdx
---
title: "Hallo Welt"
description: "Ein erster Beitrag, der die Welt ausführlich begrüßt, weil das Schema fünfzig Zeichen verlangt."
author: jane
publishedAt: "2026-01-15"
---

Der Textkörper besteht aus MDX. Sowohl **Markdown** als auch Komponenten funktionieren einwandfrei.
```

Der Dateiname (`hello-world`) ist der englische Slug. `publishedAt` ist eines der integrierten Felder, die für jeden Typ verfügbar sind; siehe [Content-Modell](/docs/content-model).

## 3. Validieren

Nach einem `pnpm install` steht dir die `scribe` CLI über deinen PATH zur Verfügung (genau wie `next`):

```bash
pnpm scribe validate
pnpm scribe status
```

Schalte den Befehl vor deinen Build-Prozess:

```json
{
  "scripts": {
    "build": "scribe validate && <dein-framework-build>"
  }
}
```

## 4. Inhalte auslesen

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

const scribe = createScribe(config);

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

Die Typisierung für `document.frontmatter` wird direkt aus deinem Zod-Schema abgeleitet. Den kompletten Funktionsumfang findest du unter [Runtime API](/docs/runtime-api).

## 5. Übersetzen

```bash
export GEMINI_API_KEY=...   # oder trage es in die .env ein
npx scribe translate --locale fr
```

Scribe spürt jede französische Seite auf, die fehlt oder veraltet ist, übersetzt alle mit `field.translatable()` markierten Felder und speichert das Ergebnis in `.scribe/store.sqlite`. **Commite dieses Verzeichnis**; setze `.scribe/` niemals auf die `.gitignore`. Weitere Details unter [Übersetzung](/docs/translation).
