Datenbanken
Auf welchen Content-Datenbank-Adaptern eine duxt-Website laufen kann, welche davon geprüft sind und die eine Regel, die die Ebene aus dem Weg hält.
Content v3 hält seine Seiten in SQL und kann mit fünf Datenbanken sprechen. duxt hat zu keiner davon eine Meinung: Der Adapter ist die Entscheidung deines Deployments, Content besitzt die Schnittstelle bereits, und die einzige Aufgabe der Ebene ist es, nicht im Weg zu stehen.
Diese Seite sagt, wie weit das tatsächlich geprüft wurde, statt es anzudeuten.
Zwei Datenbanken, nicht eine
Fast jede Überraschung in diesem Bereich entsteht daraus, „die Datenbank“ als eine Sache zu lesen. Content hält zwei, und sie haben unterschiedliche Lebensdauern und unterschiedliche Typen.
content._localDatabase | content.database | |
|---|---|---|
| Was sie hält | Den Parse-Cache — eine Zeile je Datei, wie geparst | Die Collections, die die Website abfragt |
| Wann sie existiert | Während eines Builds, in .data/content/ | Auf dem deployten Server |
| Welche Adapter | sqlite oder d1, und sonst nichts | Jeder der fünf unten |
| Wer sie liest | duxt report, der Build-Validator, die Redirect-Map | queryCollection(), bei einer Anfrage |
Die Konsequenz ist der nützliche Teil: Die Wahl eines Adapters ändert die deployte Datenbank und sonst nichts. Eine Website, die auf PostgreSQL deployt ist, baut weiterhin über einen lokalen SQLite-Parse-Cache, weil Contents eigener Typ für diesen Cache nichts anderes zulässt.
.data/content/contents.sqlite, in dem Verzeichnis, in dem du baust. Es ist ein
Cache — ihn zu löschen kostet einen Build, niemals Inhalte.
Die Adapter
content.database.type in deiner eigenen nuxt.config.ts. duxt setzt es für
keine Website; es nicht zu setzen gibt dir Contents Standard.
| Adapter | Braucht installiert | duxt |
|---|---|---|
sqlite (Standard) | Nichts auf Node 24 — gelesen über das eingebaute node:sqlite | In CI bei jedem Commit geprüft |
d1 | Nichts; ein Cloudflare-Binding | Geprüft — diese Website läuft darauf |
libsql | @libsql/client | In CI geprüft |
postgresql | pg | In CI geprüft |
pglite | @electric-sql/pglite | Ungeprüft |
„In CI geprüft“ bedeutet einen Build der eigenen Website dieses Repositorys
gegen diesen Adapter, gefolgt von einer Prüfung jedes Endpunkts, der die
Datenbank zur Laufzeit liest, und einem Lauf von duxt report. Der Workflow ist
.github/workflows/adapters.yml; er läuft bei jedem Pull Request, damit die
Zeilen oben nicht stillschweigend aufhören können, wahr zu sein.
Es ist nichts bekannt, was daran falsch wäre. Es ist aber auch nichts bekannt, was daran richtig wäre — es hatte keinen eigenen Lauf, also ist es als ungeprüft markiert, statt so zu tun, als funktioniere es. Wenn du darauf deployst, würde die Ebene gerne hören, wie es lief.
Kein nativer SQLite-Treiber wird installiert
Contents eigener Standard ist better-sqlite3, ein natives Addon, das über
node-gyp kompiliert. duxt setzt content.experimental.sqliteConnector auf
'native', was stattdessen das in Node 24 eingebaute node:sqlite verwendet und
überhaupt kein Paket braucht — weshalb die Installation der Ebene keinen Compiler
mitzieht und weshalb der Build Node 24 möchte.
Diese Einstellung erbst du, indem du die Ebene erweiterst, und du solltest dafür
nie eine Deprecation-Warnung sehen. Verworfen hat Content das ältere
experimental.nativeSqlite; duxt hat einen Test, der Contents eigene
Deklarationen liest und die Prüfungen der Ebene scheitern lässt, sobald etwas
unter content.experimental ein @deprecated trägt — die nächste Umbenennung
landet also in diesem Repository statt in deinem Build-Log.
Was während des Builds läuft und nie auf dem Server
Drei Teile der Ebene lesen unmittelbar vom Dateisystem. Alle drei laufen innerhalb eines Builds, und genau das macht einen Worker — oder jedes andere Ziel ohne Festplatte — überhaupt erst möglich.
| Was er tut | Wann | |
|---|---|---|
content-cache.ts | Öffnet den Parse-Cache mit node:sqlite und versetzt ihn in den WAL-Modus | Build |
modules/git-meta.ts | Führt git log über den Checkout aus, für „zuletzt aktualisiert“ und Mitwirkende | Build |
duxt report | Liest denselben Parse-Cache von der Kommandozeile | Neben dem Build |
Keiner von ihnen ist von einer Anfrage aus erreichbar, und keiner ist von deinem
Adapter betroffen: Sie lesen den oben beschriebenen lokalen SQLite-Cache, der
existiert, ganz gleich was content.database sagt.
Die Regel
Die Ebene liest die Content-Datenbank zur Laufzeit nie durch etwas anderes als
queryCollection().
Das ist die gesamte Adapter-Kompatibilität von duxt. In dem Moment, in dem eine Server-Route die Datenbank selbst öffnete, begänne die Ebene, ein Dateisystem und einen SQLite-Dialekt anzunehmen — und sie würde in deinem Deployment scheitern statt in den Tests dieses Repositorys.
Sie wird erzwungen statt versprochen: tests/content-database.test.ts schlägt
fehl, wenn irgendeine Datei unter server/ oder app/ einen Datenbanktreiber
importiert, und hält die Liste der Build-Zeit-Dateien, die einen öffnen dürfen,
geschlossen — eine neue muss also schriftlich begründet werden, bevor sie
landet.
Was bei einer Anfrage die Datenbank liest
Alles andere, was eine duxt-Website ausliefert, ist zum Zeitpunkt der Auslieferung eine Datei. Diese hier sind es nicht, und diese hier prüft die Adapter-Matrix:
…/page.md— die Markdown-Quelle hinter „Als Markdown ansehen“ und den Übergabe-Links./mcp— jedes Werkzeug, da jedes aus einer Collection antwortet./llms.txtund/llms-full.txt— beide laufen über jede Collection./rss.xml, sobald du es konfigurierst.
Eine Seite steht bei einem serverseitig gerenderten Deployment ebenfalls auf dieser Liste und bei einem vorgerenderten nicht. Siehe Eine Website deployen für die Frage, welches von beiden du betreibst.