---
order: 2
section: guides
title: Konfiguration
description: >-
  Alle Optionen für scribe.config.ts: Projekteinstellungen, Inhaltstypen,
  Feldmarkierungen und lokales Routing.
noindex: false
canonicalPath: /de/docs/configuration
---
Alles befindet sich in einer einzigen Datei, `scribe.config.ts`, die `defineConfig({...})` exportiert. Sowohl die Laufzeitumgebung (`createScribe`) als auch die CLI (welche `scribe.config.ts` im Arbeitsverzeichnis sucht) lesen dieselbe Datei.

## Project options

```ts
export default defineConfig({
  rootDir: ".",
  contentDir: "content",             // default
  store: ".scribe/store.sqlite",     // default
  assetsDir: "public",               // optional
  locales: ["en", "fr", "de"],
  defaultLocale: "en",               // default
  localeRouting: { strategy: "path-prefix", prefixDefaultLocale: false },
  localeFallbacks: true,             // default
  localePresets: { active: ["fr"] },
  translate: { /* see the translation page */ },
  types: [ /* defineContentType(...) */ ],
});
```

| Option | Default | Description |
| --- | --- | --- |
| `rootDir` | (Erforderlich) | Projektstammverzeichnis. Pfad relativ angeben (meistens `"."`): Die CLI löst ihn relativ zum Verzeichnis der Konfigurationsdatei auf, `createScribe` relativ zu `process.cwd()`. Den Pfad nicht aus `import.meta.url` generieren. Bundler binden diesen Pfad zur Build-Zeit direkt ein, was auf Serverless-Plattformen wie Vercel zu Fehlern führt. |
| `contentDir` | `"content"` | Verzeichnis, das für jeden Inhaltstyp einen eigenen Ordner enthält. |
| `store` | `".scribe/store.sqlite"` | SQLite-Datenbank für Übersetzungen. **Unbedingt committen, `.scribe/` nicht in die gitignore aufnehmen.** |
| `assetsDir` | (Leer) | Stammverzeichnis für statische Assets (beispielsweise `"public"`). Wenn gesetzt, warnt `scribe validate` vor Bildpfaden im Frontmatter oder Text, die physisch nicht existieren. |
| `locales` | (Erforderlich) | Alle unterstützten Sprachen (Locales), inklusive der Standardsprache. |
| `defaultLocale` | `"en"` | Die primäre Quellsprache. Muss in `locales` enthalten sein. |
| `localeRouting` | path-prefix, unprefixed default | Legt fest, wie Sprachkürzel in generierten URLs erscheinen. Bei `path-prefix` wird die Sprache vorangestellt (die Standardsprache wird weggelassen, sofern `prefixDefaultLocale` nicht auf true steht). Bei `search-param` wird `?param=locale` für alle abweichenden Sprachen angehängt. |
| `localeFallbacks` | `true` | Leitet Fallback-Ketten automatisch aus den Sprach-Tags ab. Eine regionale Variante ohne eigene Übersetzung erhält so zunächst die Übersetzung der Hauptsprache (so fällt `pt-BR` auf `pt` zurück), bevor auf die Standardsprache zurückgegriffen wird. Zum Deaktivieren auf `false` setzen. Weitere Details unter [Fallback-Ketten für Sprachen](#locale-fallback-chains). |
| `localePresets` | (Leer) | Benannte Sprachgruppen für den Befehl `scribe translate --preset name`. |
| `translate` | (Leer) | Projektweite Standardwerte für Übersetzungen ([Übersetzung](/docs/translation)). |
| `types` | (Erforderlich) | Definitionen der Inhaltstypen. |

Konfigurationen werden im Vorfeld validiert. Eine unbekannte `defaultLocale`, doppelte Typ-IDs oder eine fehlerhafte `path`-Vorlage werfen sofort einen Fehler mit einer eindeutigen Meldung.

## Content type options

```ts
defineContentType({
  id: "blog",
  schema: blogSchema,
  path: "/blog/{slug}",
  contentDir: "blog",          // default: the id
  slugStrategy: "localized",   // default: "fixed"
  indexFallback: "en",         // default: "en" if path is set, else "none"
  orderBy: "-publishedAt",     // default: "slug"
  label: "Blog",               // default: capitalized id (studio UI only)
  crossValidate: (data, ctx) => [],
  translate: { /* per-type overrides */ },
})
```

| Option | Description |
| --- | --- |
| `id` | Eindeutige ID. Dient als typisierter Zugriff (`scribe.blog`) und als standardmäßiges `contentDir`. |
| `schema` | Zod-Objektschema für das Frontmatter mit den unten stehenden Feldmarkierungen. |
| `path` | URL-Vorlage mit genau einem `{slug}` (etwa `/blog/{slug}`). Bei reinen Referenztypen (wie Autoren oder Kategorien), die keine eigenen Seiten haben, einfach weglassen. |
| `contentDir` | Ordner innerhalb des projektweiten `contentDir`, der die `.mdx`-Dateien für diesen Typ enthält. |
| `slugStrategy` | `"fixed"` bedeutet, dass jede Sprache den englischen Slug verwendet. Bei `"localized"` erstellt der Übersetzer einen individuellen Slug pro Sprache (`/de/blog/hallo-welt`). |
| `indexFallback` | Bestimmt die Rückgabe von `resolve()`, wenn für eine Sprache keine Übersetzung vorliegt. `"en"` liefert das englische Dokument (mit `actualLocale: "en"`), `"none"` gibt nichts zurück. |
| `orderBy` | Standard-Sortierung für `list()`. Mögliche Werte sind `"slug"`, `"publishedAt"`, `"-publishedAt"`, `"updatedAt"`, `"-updatedAt"` oder eine Vergleichsfunktion `(a, b) => number` für vollständig typisierte Dokumente. |
| `crossValidate` | Zusätzliche Validierung durch `scribe validate`. Erhält das geparste und typisierte Frontmatter. Als Rückgabe wird `{ field, message, level }[]` erwartet. |
| `translate` | Individuelle Übersetzungs-Prompts, Regeln oder Modelle pro Typ ([Übersetzung](/docs/translation)). |

## Field markers

Jedes Schema-Feld gehört zu einer von drei Kategorien. Unmarkierte Felder werden standardmäßig als **strukturell** behandelt.

```ts
import { field } from "scribe-cms";

const schema = z.object({
  // Sent to the translator, stored per locale:
  title: field.translatable(z.string().min(1)),

  // English-only; copied from the EN document into every locale:
  heroImage: field.structural(z.string().optional()),

  // English slug reference(s) to another content type:
  author: field.relation("author"),
  relatedPosts: field.relation("blog", { multiple: true, max: 4, optional: true }),
});
```

Übersetzbare Markierungen funktionieren auch bei Feldern, die in einfachen Arrays oder Objekten verschachtelt sind (etwa `sections.*.title`). Wichtig ist nur, das umgebende Array nicht mit `field.structural` zu umschließen, da sonst der gesamte Teilbaum nur auf Englisch verfügbar bleibt.

### `field.relation(typeId, options?)`

| Option | Default | Description |
| --- | --- | --- |
| `multiple` | `false` | Das Feld ist ein Array von Slugs. |
| `optional` | `false` | Das Feld darf weggelassen werden. `related()` gibt dann `null` zurück (bei Einzelwerten) oder überspringt fehlende Einträge (bei mehreren Werten). |
| `min` / `max` | (Leer) | Begrenzungen für die Anzahl der Einträge (nur bei `multiple: true`). |

Einschränkungen gehören in das Optionen-Objekt, nicht in verkettete Zod-Methoden. Eine Verkettung (wie `.max(8)` oder `.optional()`) klont das Schema und würde dabei die Metadaten der Relation entfernen.

Relationen speichern grundsätzlich die **englischen Slugs** und werden von `scribe validate` geprüft. Eine fehlende Referenz bei einer Pflichtrelation führt zu einem Fehler, der den Build-Prozess stoppt. Bei einer optionalen Relation wird lediglich eine Warnung ausgegeben. Zur Laufzeit werden sie mit `related()` aufgelöst (siehe [Laufzeit-API](/docs/runtime-api)).

## Locale fallback chains

Standardmäßig wird für eine regionale Sprache ohne eigene Übersetzung die Basissprache ausgeliefert, bevor auf die Standardsprache zurückgegriffen wird. Jede Sprache testet nacheinander die kürzeren Präfixe des eigenen Tags, die ebenfalls in `locales` definiert sind. So fällt `fr-CA` auf `fr` zurück und `zh-Hant-TW` probiert erst `zh-Hant` und dann `zh`. Dies lässt sich mit `localeFallbacks: false` deaktivieren. Die Standardsprache ist niemals Teil einer solchen Kette. Sie bleibt der finale Fallback, welcher über den `indexFallback` des Typs geregelt wird.

Diese Fallbacks gelten für `resolve()` (die tatsächlich ausgelieferte Sprache steht in `actualLocale`, und Slug-Weiterleitungen nutzen den Slug der Fallback-Sprache) sowie für `staticParams()` (vorab gerenderte Slugs entsprechen dem, was `resolve()` liefert). Für `get()`, `list()`, `translation()`, `alternates()` oder die Sitemap gelten sie ganz bewusst **nicht**. Diese erfordern weiterhin einen exakten Treffer.

## Typed client types

Für anwendungsseitige Typ-Aliase lässt sich alles direkt aus der Konfiguration ableiten:

```ts
import type { ScribeClient, ScribeDocs } from "scribe-cms/runtime";
import config from "./scribe.config";

type MyScribe = ScribeClient<typeof config>;
type BlogDoc = ScribeDocs<typeof config>["blog"];
```
