gcampes
Back

ctkit: Schema-as-Code für Contentful

May 15, 2026 today at 12:00 AM

contentfulopen-sourceaideveloper-toolstypescript

Der Punkt, an dem es kippt

Bei der Arbeit haben wir über 100 Content Types in Contentful. Viele davon sind Geschwister. Sie teilen dieselben Felder, dieselben Validierungen, dieselben Hilfstexte für Redakteure, dieselben erlaubten Embedded Entries. Konsistenz über alle hinweg ist das, was das System am Laufen hält.

Das von Hand zu pflegen ist ein Albtraum. Ein Tippfehler in einer Validierung. Eine falsche Checkbox. Ein Copy-Paste, bei dem du vergessen hast, ein Feld zu aktualisieren. Deine Standardisierung ist weg, und das Vertrauen in denjenigen, der es eingerichtet hat, gleich mit.

Ich habe ein Projekt geleitet, das 15 neue Content Types brauchte. Drei Spezifizierungsebenen, fünf Varianten. Überall dieselben Felder, nur eine Ebene mit abweichenden Validierungen. Das sind grob gerechnet 150 Felder, die du von Hand konfigurieren müsstest. Feldnamen, Validierungen, Rich-Text-Einstellungen, Hilfstexte. Jedes einzelne eine Gelegenheit, etwas falsch zu machen.

Das klicke ich nicht alles durch.


Contentful ist einfach eine Datenbank

Was zu wenige sagen: Contentful ist einfach eine Datenbank mit einer UI drüber. Eine nette UI, manchmal. Aber trotzdem eine Datenbank. Und das Problem "Datenbank-Schema im Code verwalten" haben wir schon vor Jahren gelöst.

Drizzle Kit macht das für SQL-Datenbanken. Du definierst dein Schema in TypeScript, führst einen Befehl aus, und es generiert Migrations. Deine Schema-Datei ist die einzige Wahrheit. Du kannst sie lesen, diffen, in einem PR reviewen und genau wissen, wie deine Datenbank gerade aussieht.

Das wollte ich für Contentful. Ich war überrascht, dass es so etwas nicht gab. Also habe ich ctkit gebaut. Content Type Kit.

Der Name hat ein paar Iterationen durchgemacht. Der erste Prototyp hieß "Can'tentful" — ich fühlte mich von Contentfuls Interface eingeschränkt. Das klang etwas aggressiv. "Schemful" hatte keine gute Domain. "ctkit" blieb hängen: funktioniert als "Content Type Kit" und als "Contentful Kit." Wer weiß, vielleicht ist Contentful nur der Anfang.


Die Migrations-Falle

Contentful hat eine eigene Migration CLI. Ich habe sie ausprobiert. Claude die Migrationsskripte schreiben lassen. Hat funktioniert, technisch gesehen.

Aber es gibt ein grundsätzliches Problem: Migrations geben dir nur Diffs, nie das Gesamtbild. Um zu verstehen, wie ein Content Type heute aussieht, musst du jede Migration nachspielen, die ihn jemals berührt hat.

Das ist wie ein Git-Repo, in dem du nur Commits sehen kannst, aber nie die eigentlichen Dateien. Du kannst die Historie der Änderungen nachverfolgen, aber du bekommst nie einen sauberen Snapshot des aktuellen Stands. Das ist keine Quelle der Wahrheit. Das ist Archäologie.

Ich wollte .ts-Dateien, die ich öffnen und sofort sehen kann: jedes Feld, jede Validierung, jede Einstellung. Das komplette Bild.


Der Workflow

Installier @ctkit/cli, starte ctkit init, und du bekommst ein kleines Beispiel: einen einzelnen blogPost Content Type mit bereits generierter Migration. Führe ctkit migrate aus und der Typ taucht in deinem Contentful Space auf.

Der eigentliche Moment kommt, wenn du deinen eigenen Typ erstellst, pushst, und dann etwas anpassen musst. Eine Validierungsänderung. Ein neuer erlaubter Entry Type. Eine Zeile in deiner Schema-Datei ändern, zwei CLI-Befehle, fertig. Kein Durchklicken von 10 Screens. Kein Risiko, eine Checkbox falsch zu setzen.

import { defineContentType, FieldType } from "@ctkit/core";
 
export const blogPost = defineContentType({
  id: "blogPost",
  name: "Blog Post",
  fields: [
    { id: "title", name: "Title", type: FieldType.SYMBOL, required: true },
    { id: "slug", name: "Slug", type: FieldType.SYMBOL, required: true },
    { id: "body", name: "Body", type: FieldType.RICH_TEXT },
  ],
});

Das ist deine Quelle der Wahrheit. Lesbar, diffbar, reviewbar.


KI schreibt dein Content Model

Das ist der eigentliche Superpower. Weil dein Content Model einfach TypeScript ist, kann KI es verwalten. KI kann Code schreiben. KI kann die ctkit-Dokumentation lesen. Sie schreibt Schemas besser als du, und besser als ich. Und anders als in einer UI rumzuklicken, kannst du der KI eine Beschreibung geben und bekommst in Sekunden ein valides, konsistentes Schema zurück.


Wie ctkit gebaut wurde

Ich habe keine einzige Zeile von ctkit selbst geschrieben. Claude hat gebaut. Ich war der Architekt: lange Planungssessions, um die CLI-Schnittstelle, die Schema-API, die Homepage und die Docs auszuarbeiten. Dann hat Claude jede Zeile TypeScript geschrieben, jeden Test, jede Dokumentationsseite.

Der grobe Prototyp entstand in der zweiten Jahreshälfte 2025. Eine Woche Prompting mit Sonnet. Dieser Prototyp hat die Content Types erstellt, die jetzt auf seatgeek.com laufen und Millionen von Seiten ausliefern. Zu dem Zeitpunkt war es ein hemdsärmeliges Tool, das nur für meinen Use Case funktionierte.

Im Mai 2026 habe ich einen einzigen Tag investiert, um alles zu produktionisieren. Das Monorepo in @ctkit/cli und @ctkit/core aufgeteilt. Eine Homepage, eine Docs-Seite und ein Demo-Video gebaut. Alles in einer Session. Der Abstand zwischen "grober Prototyp" und "veröffentlichtes Open-Source-Tool" schrumpfte von Monaten auf Stunden. Die KI wurde besser, und meine Fähigkeit, sie zu steuern, auch.


Was kommt als Nächstes

Gerade liegt mein Fokus darauf, den Core kugelsicher zu machen. Stresstests für Content-Model-Erstellung, Updates, Feldänderungen, Löschungen und Edge Cases bei Migrations. Irgendwann auch Data Migrations. Die Art von langweiliger, aber unverzichtbarer Arbeit, die ein Tool vertrauenswürdig macht.

Außerdem arbeite ich daran, die Adoption einfacher zu machen für Leute, die schon einen Contentful Space voller Content Types haben. ctkit hat einen pull-Befehl, der dein bestehendes Content Model in Schema-Dateien importiert, damit du nicht bei null anfangen musst. Das ist die Brücke zwischen "Ich nutze Contentful seit Jahren" und "Jetzt ist mein Content Model im Code."

ctkit muss kugelsicher sein, bevor es wachsen darf.


Probier's aus

Der Code liegt auf GitHub: gcampes/ctkit. Die CLI ist auf npm als @ctkit/cli, und die Core-Types und Konstanten unter @ctkit/core. Docs und Homepage unter gcampes.github.io/ctkit.

Gebaut mit Claude über OpenCode. Inspiriert von Drizzle Kit.