Content v3 conserve ses pages en SQL et sait parler à cinq bases de données.
duxt n’a d’avis sur aucune d’elles : l’adaptateur relève de votre déploiement,
Content possède déjà cette surface, et le seul travail de la couche est de ne pas
gêner.

Cette page dit jusqu’où cela a réellement été vérifié, au lieu de le laisser
entendre.

## Deux bases de données, pas une

Presque toutes les surprises dans ce domaine viennent de ce qu’on lit « la base
de données » comme une seule chose. Content en tient deux, et elles n’ont ni la
même durée de vie ni le même type.

| | `content._localDatabase` | `content.database` |
| :--- | :--- | :--- |
| Ce qu’elle contient | Le cache d’analyse — une ligne par fichier, tel qu’analysé | Les collections que le site interroge |
| Quand elle existe | Pendant une compilation, dans `.data/content/` | Sur le serveur déployé |
| Quels adaptateurs | `sqlite` ou `d1`, et rien d’autre | N’importe lequel des cinq ci-dessous |
| Qui la lit | `duxt report`, le validateur de compilation, la table de redirections | `queryCollection()`, sur une requête |

La conséquence est la partie utile : **choisir un adaptateur change la base de
données déployée et rien d’autre.** Un site déployé sur PostgreSQL compile
toujours à travers un cache d’analyse SQLite local, parce que le type que
Content donne lui-même à ce cache n’admet rien d’autre.

::callout{type="info" title="Où vit le cache"}
`.data/content/contents.sqlite`, dans le répertoire où vous compilez. C’est un
cache : le supprimer coûte une compilation, jamais du contenu.
::

## Les adaptateurs

`content.database.type` dans votre propre `nuxt.config.ts`. duxt ne le fixe pour
aucun site ; le laisser vide vous donne la valeur par défaut de Content.

| Adaptateur | Doit être installé | duxt |
| :--------- | :----------------- | :--- |
| `sqlite` (par défaut) | Rien sur Node 24 — lu via le `node:sqlite` intégré | Vérifié en CI à chaque commit |
| `d1` | Rien ; un binding Cloudflare | Vérifié — ce site tourne dessus |
| `libsql` | `@libsql/client` | Vérifié en CI |
| `postgresql` | `pg` | Vérifié en CI |
| `pglite` | `@electric-sql/pglite` | **Non testé** |

« Vérifié en CI » signifie une compilation du site de ce dépôt contre cet
adaptateur, suivie d’une sonde de chaque point d’entrée qui lit la base de
données à l’exécution et d’une exécution de `duxt report`. Le workflow est
`.github/workflows/adapters.yml` ; il tourne à chaque pull request, de sorte que
les lignes ci-dessus ne peuvent pas cesser d’être vraies en silence.

::callout{type="warning" title="PGlite est non testé, pas cassé"}
Rien n’y est connu comme défaillant. Rien n’y est connu comme fonctionnel non
plus — il n’a pas eu d’exécution dédiée, il est donc marqué non testé plutôt que
présenté comme fonctionnel. Si vous déployez dessus, la couche aimerait savoir
comment cela s’est passé.
::

### Aucun pilote SQLite natif n’est installé

La valeur par défaut de Content est `better-sqlite3`, un module natif compilé
par node-gyp. duxt règle `content.experimental.sqliteConnector` sur `'native'`,
qui utilise à la place le `node:sqlite` intégré à Node 24 et ne demande aucun
paquet — d’où le fait que l’installation de la couche n’entraîne aucun
compilateur et que la compilation réclame Node 24.

Vous héritez de ce réglage en étendant la couche, et vous ne devriez jamais voir
d’avertissement d’obsolescence à son sujet. Ce que Content a déprécié, c’est
l’ancien `experimental.nativeSqlite` ; duxt dispose d’un test qui lit les
déclarations de Content elles-mêmes et fait échouer les vérifications de la
couche dès que quelque chose qu’elle fixe sous `content.experimental` porte une
étiquette `@deprecated` — le prochain renommage atterrit donc dans ce dépôt
plutôt que dans votre journal de compilation.

## Ce qui s’exécute pendant la compilation, et jamais sur le serveur

Trois parties de la couche lisent directement le système de fichiers. Toutes
trois s’exécutent à l’intérieur d’une compilation, ce qui est précisément ce qui
rend possible un Worker — ou toute cible sans disque.

| | Ce que cela fait | Quand |
| :--- | :--- | :--- |
| `content-cache.ts` | Ouvre le cache d’analyse avec `node:sqlite` et le passe en mode WAL | Compilation |
| `modules/git-meta.ts` | Lance `git log` sur la copie de travail pour « dernière mise à jour » et les contributeurs | Compilation |
| `duxt report` | Lit ce même cache depuis la ligne de commande | À côté de la compilation |

Aucune n’est joignable depuis une requête, et aucune n’est affectée par votre
adaptateur : elles lisent le cache SQLite local décrit plus haut, qui existe quoi
que dise `content.database`.

## La règle

> La couche ne lit jamais la base de données de Content à l’exécution autrement
> que par `queryCollection()`.

C’est là toute la compatibilité d’adaptateurs de duxt. Dès l’instant où une
route serveur ouvrirait la base elle-même, la couche se mettrait à supposer un
système de fichiers et un dialecte SQLite — et elle échouerait dans votre
déploiement plutôt que dans les tests de ce dépôt.

Elle est imposée plutôt que promise : `tests/content-database.test.ts` échoue si
un fichier sous `server/` ou `app/` importe un pilote de base de données, et
garde close la liste des fichiers de compilation autorisés à en ouvrir un — un
nouveau doit donc être justifié par écrit avant d’entrer.

### Ce qui lit la base de données sur une requête

Tout le reste de ce qu’un site duxt sert est déjà un fichier au moment où il est
servi. Ceci ne l’est pas, et c’est ce que sonde la matrice d’adaptateurs :

- **`…/page.md`** — la source Markdown derrière « Voir en Markdown » et les liens
  de transmission.
- **`/mcp`** — chaque outil, puisque chacun répond depuis une collection.
- **`/llms.txt` et `/llms-full.txt`** — tous deux parcourent chaque collection.
- **`/rss.xml`**, une fois que vous le configurez.

Une page figure elle aussi sur cette liste dans un déploiement rendu côté
serveur, et pas dans un déploiement prérendu. Voir
[Déployer un site](/guides/deploy-a-site) pour savoir lequel des deux vous
faites tourner.