Options de base de données

Sur cette page

EmDash prend en charge plusieurs backends de base de données. Choisissez en fonction de votre cible de déploiement.

Vue d’ensemble

Base de donnéesIdéal pourDéploiement
D1Cloudflare WorkersEdge, distribué globalement
HyperdrivePostgreSQL sur Cloudflare WorkersEdge, Postgres existant
PostgreSQLProduction Node.jsToute plateforme avec Postgres
libSQLBases de données distantesEdge ou Node.js
SQLiteNode.js, développement localServeur unique

Cloudflare D1

D1 est la base de données SQLite serverless de Cloudflare. Utilisez-la lors du déploiement sur Cloudflare Workers.

import { d1 } from "@emdash-cms/cloudflare";

export default defineConfig({
	integrations: [
		emdash({
			database: d1({ binding: "DB" }),
		}),
	],
});

Configuration

OptionTypePar défautDescription
bindingstringNom du binding D1 de wrangler.jsonc
sessionstring"disabled"Mode de réplication de lecture (voir ci-dessous)
bookmarkCookiestring"__em_d1_bookmark"Nom du cookie pour les bookmarks de session

Mise en place

wrangler.jsonc

{
  "d1_databases": [
    {
      "binding": "DB",
      "database_name": "emdash-db"
    }
  ]
}

wrangler.toml

[[d1_databases]]
binding = "DB"
database_name = "emdash-db"

Read Replicas

D1 prend en charge la réplication de lecture pour réduire la latence de lecture des sites distribués globalement. Lorsqu’elle est activée, les requêtes de lecture sont routées vers des répliques proches au lieu de toujours interroger la base de données primaire.

EmDash utilise l’API D1 Sessions pour gérer cela de manière transparente. Activez-la avec l’option session :

import { d1 } from "@emdash-cms/cloudflare";

export default defineConfig({
	integrations: [
		emdash({
			database: d1({
				binding: "DB",
				session: "auto",
			}),
		}),
	],
});

Modes de session

ModeComportement
"disabled"Pas de sessions. Toutes les requêtes vont à la primaire. Par défaut.
"auto"Les requêtes anonymes lisent depuis la réplique la plus proche. Les utilisateurs authentifiés obtiennent la cohérence read-your-writes via des cookies de bookmark.
"primary-first"Comme "auto", mais la première requête va toujours à la primaire. Pour les sites avec des écritures très fréquentes.

Fonctionnement

  • Les visiteurs anonymes obtiennent first-unconstrained — les lectures vont à la réplique la plus proche pour la latence la plus basse. Les utilisateurs anonymes n’écrivant jamais, ils n’ont pas besoin de garanties de cohérence.
  • Les utilisateurs authentifiés (éditeurs, auteurs) obtiennent des sessions basées sur les bookmarks. Après une écriture, un cookie de bookmark garantit que la requête suivante voit au moins cet état.
  • Les requêtes d’écriture (POST, PUT, DELETE) commencent toujours à la base de données primaire.
  • Les requêtes au moment du build (Astro content collections) contournent entièrement les sessions et utilisent directement la primaire.

libSQL

libSQL est un fork de SQLite qui prend en charge les connexions distantes. Utilisez-le quand vous avez besoin d’une base de données distante sans Cloudflare D1.

import { libsql } from "emdash/db";

export default defineConfig({
	integrations: [
		emdash({
			database: libsql({
				url: process.env.LIBSQL_DATABASE_URL,
				authToken: process.env.LIBSQL_AUTH_TOKEN,
			}),
		}),
	],
});

Configuration

OptionTypeDescription
urlstringURL de base de données (libsql://... ou file:...)
authTokenstringToken d’auth pour les bases distantes (optionnel en local)

Développement local

Utilisez un fichier libSQL local pendant le développement :

database: libsql({ url: "file:./data.db" });

PostgreSQL

PostgreSQL est pris en charge pour les déploiements Node.js nécessitant une base de données relationnelle complète.

import { postgres } from "emdash/db";

export default defineConfig({
	integrations: [
		emdash({
			database: postgres({
				connectionString: process.env.DATABASE_URL,
			}),
		}),
	],
});

Configuration

Vous pouvez vous connecter avec une chaîne de connexion ou des paramètres individuels :

// Chaîne de connexion
database: postgres({
	connectionString: "postgres://user:password@localhost:5432/emdash",
});

// Paramètres individuels
database: postgres({
	host: "localhost",
	port: 5432,
	database: "emdash",
	user: "emdash",
	password: process.env.DB_PASSWORD,
	ssl: true,
});
OptionTypeDescription
connectionStringstringURL de connexion PostgreSQL
hoststringHôte de la base de données
portnumberPort de la base de données
databasestringNom de la base de données
userstringUtilisateur de la base de données
passwordstringMot de passe de la base de données
sslbooleanActiver SSL
pool.minnumberConnexions minimales du pool (défaut 0)
pool.maxnumberConnexions maximales du pool (défaut 10)

Pool de connexions

L’adaptateur utilise pg.Pool en interne. Ajustez la taille du pool selon votre déploiement :

database: postgres({
	connectionString: process.env.DATABASE_URL,
	pool: { min: 2, max: 20 },
});

Hyperdrive

Utilisez l’adaptateur hyperdrive() pour exécuter EmDash sur Cloudflare Workers avec une base de données PostgreSQL existante — ou compatible Postgres (ex. PlanetScale Postgres). Hyperdrive regroupe et accélère la connexion via le réseau Cloudflare ; le dialecte PostgreSQL d’EmDash exécute les requêtes.

import { hyperdrive, r2 } from "@emdash-cms/cloudflare";

export default defineConfig({
	integrations: [
		emdash({
			database: hyperdrive({ binding: "HYPERDRIVE" }),
			storage: r2({ binding: "MEDIA" }),
		}),
	],
});

Prérequis

  • pg >= 8.16.3 installé dans votre site (pnpm add pg)
  • compatibility_flags: ["nodejs_compat"]
  • compatibility_date >= "2024-09-23"

Mise en place

Créez la configuration Hyperdrive et ajoutez le binding à votre configuration Wrangler :

wrangler hyperdrive create emdash-db \
  --connection-string "postgres://user:password@host/db?sslmode=verify-full" \
  --caching-disabled

wrangler.jsonc

{
  "hyperdrive": [
    {
      "binding": "HYPERDRIVE",
      "id": "<your-hyperdrive-id>"
    }
  ]
}

wrangler.toml

[[hyperdrive]]
binding = "HYPERDRIVE"
id = "<your-hyperdrive-id>"

Configuration

OptionTypePar défautDescription
bindingstring"HYPERDRIVE"Binding Hyperdrive primaire (cache désactivé)
cachedBindingstringBinding optionnel avec cache activé pour les lectures anonymes
maxnumber5Taille max du pool de connexions in-Worker vers Hyperdrive

Servir les lectures anonymes depuis le cache

Par défaut, vous désactivez entièrement le cache Hyperdrive, car l’admin et les écritures nécessitent la cohérence read-after-write. Mais les lectures publiques anonymes — pas de session, pas d’écriture — peuvent tolérer une courte fenêtre de données obsolètes. Si ce compromis est acceptable, exécutez deux configurations Hyperdrive sur la même base de données : une avec cache désactivé (le binding primaire) et une avec cache activé (cachedBinding). EmDash route alors les requêtes de lecture anonymes via le binding avec cache tandis que chaque requête authentifiée et chaque écriture reste sur le primaire sans cache, préservant la cohérence read-after-write.

# Primaire — cache DÉSACTIVÉ (admin, requêtes auth., écritures, migrations)
wrangler hyperdrive create emdash-db \
  --connection-string "postgres://user:password@host/db?sslmode=verify-full" \
  --caching-disabled

# Avec cache — MÊME chaîne de connexion, cache ACTIVÉ (lectures anonymes uniquement)
wrangler hyperdrive create emdash-db-cached \
  --connection-string "postgres://user:password@host/db?sslmode=verify-full"
{
	"hyperdrive": [
		{ "binding": "HYPERDRIVE", "id": "<caching-disabled-id>" },
		{ "binding": "HYPERDRIVE_CACHED", "id": "<caching-enabled-id>" }
	]
}
database: hyperdrive({ binding: "HYPERDRIVE", cachedBinding: "HYPERDRIVE_CACHED" });

C’est le pattern à deux configurations que Cloudflare documente pour le cache. EmDash décide quel binding utiliser par requête :

  • Lectures anonymes des chemins du site public (GET/HEAD, pas de session, pas sous /_emdash) → cachedBinding avec cache.
  • Requêtes authentifiées (éditeurs, auteurs) → binding sans cache.
  • Écritures (POST, PUT, DELETE, y compris anonymes) → binding sans cache.
  • Toute requête sous /_emdash (admin, setup, auth, APIs internes), même un GET anonyme → binding sans cache.
  • Migrations et démarrage à froid → toujours le binding primaire.

SQLite

SQLite avec better-sqlite3 est l’option la plus simple pour les déploiements Node.js.

import { sqlite } from "emdash/db";

export default defineConfig({
	integrations: [
		emdash({
			database: sqlite({ url: "file:./data.db" }),
		}),
	],
});

Configuration

OptionTypeDescription
urlstringChemin de fichier avec préfixe file:

Chemin de fichier

L’url doit commencer par file: :

// Chemin relatif
database: sqlite({ url: "file:./data/emdash.db" });

// Chemin absolu
database: sqlite({ url: "file:/var/data/emdash.db" });

// Depuis une variable d'environnement
database: sqlite({ url: `file:${process.env.DATABASE_PATH}` });

Migrations

EmDash exécute les migrations automatiquement à la première requête, pour chaque dialecte supporté (D1, SQLite, libSQL, PostgreSQL). Les migrations sont intégrées au package emdash et embarquées dans votre build.

Si la base de données est vide (pas de collections) et que l’assistant de configuration n’a pas été complété, EmDash applique également un fichier seed au premier démarrage. Le seed est lu depuis .emdash/seed.json, le chemin dans package.json#emdash.seed, ou seed/seed.json — le premier trouvé — et intégré au build à la compilation. Si aucun n’est présent, un seed par défaut intégré est utilisé. Les démarrages ultérieurs contre une base de données existante laissent son contenu intact.

Configuration basée sur l’environnement

Utilisez différentes bases de données par environnement :

import { sqlite, libsql, postgres } from "emdash/db";
import { d1 } from "@emdash-cms/cloudflare";

const database = import.meta.env.PROD ? d1({ binding: "DB" }) : sqlite({ url: "file:./data.db" });

export default defineConfig({
	integrations: [emdash({ database })],
});

Le choix peut aussi être basé sur une variable d’environnement plutôt que le mode de build :

const database = process.env.DATABASE_URL
	? postgres({ connectionString: process.env.DATABASE_URL })
	: sqlite({ url: "file:./data.db" });