Datenbank auswählen

Auf dieser Seite

Wählen Sie einen Datenbankadapter pro Deployment. Die Datenbank speichert das Inhaltsmodell, Einträge, Benutzer, Einstellungen und Plugin-Daten. Mediendateien gehören in ein separates Speicher-Backend.

Übersicht

DatenbankVerwenden, wennLaufzeit
SQLiteEin Node.js-Prozess eine persistente Festplatte hatNode.js oder lokale Entwicklung
D1Die Website auf Cloudflare Workers läuft und Cloudflare SQL nutzen sollCloudflare Workers
HyperdriveDie Website auf Workers läuft und eine bestehende PostgreSQL-Quelle nutzen mussCloudflare Workers
PostgreSQLMehrere Node.js-Prozesse eine gemeinsame Datenbank benötigenNode.js
libSQLEin Node.js-Deployment eine entfernte SQLite-kompatible Datenbank benötigtNode.js

D1 ist der Standard für die Cloudflare-Vorlagen. SQLite ist die einfachste Node.js-Option, erfordert jedoch ein beschreibbares persistentes Volume und operative Datenbank-Backups.

SQLite

SQLite verwendet den in Node.js integrierten Datenbanktreiber und ist die einfachste Option für Node.js-Deployments.

import { sqlite } from "emdash/db";

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

Konfiguration

OptionTypBeschreibung
urlstringDateipfad mit file:-Präfix

Dateipfad

Die url muss mit file: beginnen:

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

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

// Aus Umgebungsvariable
database: sqlite({ url: `file:${process.env.DATABASE_PATH}` });

Cloudflare D1

D1 ist Cloudflares serverlose SQLite-Datenbank. Verwenden Sie es beim Deployment auf Cloudflare Workers.

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

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

Konfiguration

OptionTypStandardBeschreibung
bindingstringD1-Bindungsname aus wrangler.jsonc
sessionstring"disabled"Lesereplikationsmodus (siehe unten)
bookmarkCookiestring"__em_d1_bookmark"Cookie-Name für Session-Lesezeichen

Wrangler-Bindung

wrangler.jsonc

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

wrangler.toml

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

Wrangler kann eine fehlende D1-Datenbank aus dieser Bindung beim Deployment bereitstellen. EmDash-Migrationen sind ein separater Schritt. Folgen Sie Auf Cloudflare deployen für den vollständigen Bindungssatz und Core-Datenbank-Migrationen verwalten für das Migrations-Runbook.

Lesereplikate

D1 unterstützt Lesereplikation, um die Leselatenz für global verteilte Websites zu verringern. Wenn aktiviert, werden Leseabfragen an nahegelegene Replikate weitergeleitet, anstatt immer die primäre Datenbank zu treffen.

EmDash verwendet die D1 Sessions API, um dies transparent zu verwalten. Aktivieren Sie es mit der session-Option:

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

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

Session-Modi

ModusVerhalten
"disabled"Keine Sessions. Alle Abfragen gehen an die Primärdatenbank. Standard.
"auto"Anonyme Anfragen lesen vom nächstgelegenen Replikat. Authentifizierte Benutzer erhalten Lese-nach-Schreib-Konsistenz über Lesezeichen-Cookies.
"primary-first"Wie "auto", aber die erste Abfrage geht immer an die Primärdatenbank. Für Websites mit sehr häufigen Schreibvorgängen.

Funktionsweise

  • Anonyme Besucher erhalten first-unconstrained — Lesevorgänge gehen an das nächstgelegene Replikat für die niedrigste Latenz. Da anonyme Benutzer nie schreiben, benötigen sie keine Konsistenzgarantien.
  • Authentifizierte Benutzer (Redakteure, Autoren) erhalten lesezeichenbasierte Sessions. Nach einem Schreibvorgang stellt ein Lesezeichen-Cookie sicher, dass die nächste Anfrage mindestens diesen Stand sieht.
  • Schreibanfragen (POST, PUT, DELETE) beginnen immer bei der primären Datenbank.
  • Build-Zeit-Abfragen (Astro Content Collections) umgehen Sessions vollständig und nutzen die Primärdatenbank direkt.

libSQL

libSQL ist ein Fork von SQLite, der entfernte Verbindungen unterstützt. Verwenden Sie es, wenn Sie eine entfernte Datenbank ohne Cloudflare D1 benötigen.

import { libsql } from "emdash/db";

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

Konfiguration

OptionTypBeschreibung
urlstringDatenbank-URL (libsql://... oder file:...)
authTokenstringLaufzeit-Auth-Token für entfernte Datenbanken (optional für lokal)
migrationAuthTokenEnvstringMigrations-Token-Variablenname (Standard TURSO_AUTH_TOKEN)

Lokale Entwicklung

Verwenden Sie eine lokale libSQL-Datei während der Entwicklung:

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

PostgreSQL

PostgreSQL wird für Node.js-Deployments unterstützt, die eine vollständige relationale Datenbank benötigen.

import { postgres } from "emdash/db";

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

Konfiguration

Sie können eine Verbindung über einen Connection-String oder einzelne Parameter herstellen:

// Connection-String
database: postgres({
	connectionString: "postgres://user:password@localhost:5432/emdash",
});

// Einzelne Parameter
database: postgres({
	host: "localhost",
	port: 5432,
	database: "emdash",
	user: "emdash",
	password: process.env.DB_PASSWORD,
	ssl: true,
});
OptionTypBeschreibung
connectionStringstringPostgreSQL-Verbindungs-URL
hoststringDatenbankhost
portnumberDatenbankport
databasestringDatenbankname
userstringDatenbankbenutzer
passwordstringDatenbankpasswort
sslbooleanSSL aktivieren
pool.minnumberMinimale Pool-Verbindungen (Standard 0)
pool.maxnumberMaximale Pool-Verbindungen (Standard 10)
pool.connectionTimeoutMillisnumberMaximale Verbindungswartezeit (pg-Standard: 0, kein Timeout)
pool.idleTimeoutMillisnumberLebensdauer inaktiver Clients (pg-Standard: 10.000 ms)
migrationConnectionStringEnvstringMigrations-Connection-String-Variablenname (Standard DATABASE_URL)

Setzen Sie pool.connectionTimeoutMillis auf einen Wert ungleich Null, um zu begrenzen, wie lange eine Anfrage wartet, wenn PostgreSQL nicht erreichbar ist oder keine gepoolte Verbindung verfügbar wird. Setzen Sie pool.idleTimeoutMillis auf 0, um inaktive Clients offen zu halten, bis der Pool geschlossen wird. Das Weglassen beider Optionen behält den pg-Standard bei.

Anforderungen an die Datenbankrolle

EmDash erstellt und aktualisiert seine eigenen PostgreSQL-Tabellen. Core-Migrationen erstellen und ändern System- und Sammlungstabellen, Inhaltstypen erstellen ec_*-Tabellen, und das Hinzufügen oder Entfernen eines Feldes ändert die Sammlungstabelle. Die konfigurierte PostgreSQL-Rolle benötigt daher Schema-Autorität für die gesamte Lebensdauer der Website, nicht nur während der Ersteinrichtung.

Verwenden Sie eine kanonische Rolle für EmDash. Sie benötigt:

  • CONNECT auf der Datenbank;
  • USAGE und CREATE auf dem aktiven Schema;
  • Eigentümerschaft an jeder EmDash-Tabelle und -Funktion, entweder direkt oder durch Mitgliedschaft mit INHERIT in der besitzenden Rolle; und
  • SELECT, INSERT, UPDATE und DELETE auf diesen Tabellen.

Sie muss kein Superuser sein, keine CREATEDB- oder CREATEROLE-Berechtigung haben und keine Erweiterungen erstellen. PostgreSQL bietet keine ALTER- oder DROP-Tabellenberechtigung: diese Operationen gehören dem Objekteigentümer und Rollen, die dessen Privilegien erben. Das Gewähren von ALL auf eine Tabelle an eine andere Rolle macht diese Rolle nicht zum Eigentümer. EmDash führt kein SET ROLE aus, daher ist eine Mitgliedschaft ohne Vererbung nicht ausreichend.

Die meisten Installationen können das bestehende Schema der Datenbank verwenden, üblicherweise public. Dies ist die einfachste Option, wenn die Datenbank EmDash gewidmet ist. In den Beispielen unten ist emdash_app die Login-Rolle im EmDash-Connection-String; verwenden Sie eine bestehende Anbieterrolle oder erstellen Sie ein dediziertes Login. Gewähren Sie Zugriff mit einer administrativen Verbindung und ersetzen Sie Ihre Datenbank-, Schema- und Rollennamen:

GRANT CONNECT ON DATABASE app TO emdash_app;
GRANT USAGE, CREATE ON SCHEMA public TO emdash_app;

Diese Berechtigungen ermöglichen der Rolle das Erstellen neuer Objekte. Sie ändern nicht den Eigentümer bestehender Tabellen; verwenden Sie das PostgreSQL-Eigentümerschafts-Reparatur-Runbook, wenn eine bestehende Website gemischte Eigentümer hat.

EmDash verwendet PostgreSQLs aktives current_schema(). Es erstellt kein Schema und setzt keinen search_path, überprüfen Sie daher die Verbindung vor dem Deployment:

SELECT
  current_database(),
  session_user,
  current_user,
  current_schema(),
  current_setting('search_path');

Optional: Dediziertes Schema verwenden

Verwenden Sie ein dediziertes Schema, wenn EmDash eine Datenbank mit einer anderen Anwendung teilt oder wenn Sie seine Objekte von public isolieren möchten. Dies ist optional und am einfachsten vor der ersten EmDash-Einrichtung zu konfigurieren. Eine für EmDash dedizierte Datenbank benötigt kein separates Schema.

Unter der Annahme, dass die kanonische Rolle emdash_app bereits existiert, erstellen und wählen Sie ihr Schema mit einer administrativen Verbindung:

GRANT CONNECT ON DATABASE app TO emdash_app;
CREATE SCHEMA emdash AUTHORIZATION emdash_app;
ALTER ROLE emdash_app IN DATABASE app SET search_path = emdash;

Dies verschiebt keine bestehende Installation von public und repariert keine gemischte Eigentümerschaft. Bestehende Websites sollten ihr aktuelles Schema beibehalten und stattdessen das PostgreSQL-Eigentümerschafts-Reparatur-Runbook verwenden.

Verbindungspooling

Der Adapter verwendet pg.Pool. Passen Sie die Poolgröße an Ihr Deployment an:

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

Hyperdrive

Verwenden Sie den hyperdrive()-Adapter, um EmDash auf Cloudflare Workers mit einer bestehenden PostgreSQL — oder Postgres-kompatiblen (z.B. PlanetScale Postgres) — Datenbank zu betreiben. Hyperdrive poolt und beschleunigt die Verbindung über das Cloudflare-Netzwerk; EmDashs PostgreSQL-Dialekt führt die Abfragen aus.

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

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

Voraussetzungen

  • pg >= 8.16.3 in Ihrer Website installiert (pnpm add pg)
  • compatibility_flags: ["nodejs_compat"]
  • compatibility_date >= "2024-09-23"

Einrichtung

Bereiten Sie zunächst die PostgreSQL-Rolle vor. Erstellen Sie dann die Hyperdrive-Konfiguration mit dem Connection-String dieser Rolle und fügen Sie die Bindung zu Ihrer Wrangler-Konfiguration hinzu:

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

wrangler.jsonc

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

wrangler.toml

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

Konfiguration

OptionTypStandardBeschreibung
bindingstring"HYPERDRIVE"Primärer (caching-deaktivierter) Hyperdrive-Bindungsname
cachedBindingstringOptionale caching-aktivierte Bindung für anonyme Lesevorgänge (siehe unten)
preferUncachedAfterWriteMsnumber60000*Nach einer Inhaltsveröffentlichung binding für diese Dauer (ms) bei anonymen öffentlichen Lesevorgängen bevorzugen (an Hyperdrive max_age anpassen)
migrationConnectionStringEnvstringCLOUDFLARE_HYPERDRIVE_LOCAL_CONNECTION_STRING_<BINDING>Umgebungsvariable mit der direkten PostgreSQL-Quell-URL für emdash migrate
maxnumber5Maximale Größe des In-Worker-Verbindungspools zu Hyperdrive

*Standard 60000 gilt nur wenn cachedBinding gesetzt ist; ansonsten ignoriert.

Anonyme Lesevorgänge aus dem Cache bedienen

Standardmäßig deaktivieren Sie das Hyperdrive-Caching vollständig, da der Admin und Schreibvorgänge Lese-nach-Schreib-Konsistenz benötigen. Aber anonyme öffentliche Anfragen mit GET oder HEAD können ein kurzes Veralterungsfenster tolerieren. Wenn dieser Kompromiss akzeptabel ist, betreiben Sie zwei Hyperdrive-Konfigurationen über derselben Datenbank: eine mit deaktiviertem Caching (die primäre binding) und eine mit aktiviertem Caching (cachedBinding). EmDash leitet diese anonymen öffentlichen Anfragen über die cache-aktivierte Bindung und jede andere Anfrage über die nicht-gecachte Primärbindung.

# Primär — Caching AUS (für Admin, authentifizierte Anfragen, Schreibvorgänge, Migrationen)
wrangler hyperdrive create emdash-db \
  --connection-string "postgres://user:password@host/db?sslmode=verify-full" \
  --caching-disabled

# Gecacht — GLEICHE Datenbankrolle und Connection-String, Caching AN
wrangler hyperdrive create emdash-db-cached \
  --connection-string "postgres://user:password@host/db?sslmode=verify-full"
{
	"hyperdrive": [
		{ "binding": "HYPERDRIVE", "id": "<caching-deaktivierte-id>" },
		{ "binding": "HYPERDRIVE_CACHED", "id": "<caching-aktivierte-id>" }
	]
}
database: hyperdrive({ binding: "HYPERDRIVE", cachedBinding: "HYPERDRIVE_CACHED" });

Dies ist das Zwei-Konfigurationen-Muster, das Cloudflare für Caching dokumentiert. EmDash entscheidet pro Anfrage, welche Bindung verwendet wird:

  • Anonyme Lesevorgänge öffentlicher Pfade (GET/HEAD, keine Session, nicht unter /_emdash) → cache-aktivierte cachedBinding, außer für ein kurzes Fenster nach einer Inhaltsveröffentlichung (Standard 60s; setzen Sie preferUncachedAfterWriteMs auf Ihren Hyperdrive-max_age), in dem EmDash die nicht-gecachte binding bevorzugt, damit ein Rebuild nicht Edge-/Objekt-Caches aus noch veralteten Hyperdrive-Ergebnissen füllen kann.
  • Authentifizierte Anfragen (Redakteure, Autoren) → nicht-gecachte binding.
  • Mutationsanfragen (POST, PUT, PATCH, DELETE, einschließlich anonymer) → nicht-gecachte binding.
  • Alle Anfragen unter /_emdash (Admin, Einrichtung, Auth, interne APIs), auch ein anonymes GET → nicht-gecachte binding.
  • Laufzeit-Migrationen und Kaltstart → immer die primäre binding.
  • Deployment-verwaltete Migrationen → verbinden sich direkt mit der PostgreSQL-Quelle über migrationConnectionStringEnv; sie verwenden nie eine der Hyperdrive-Bindungen.

Optional: Separate gecachte Rolle verwenden

Migrationen, Einrichtung, authentifizierte Anfragen und explizite Schreibanfragen verwenden immer die primäre binding. Eine separate Rolle für cachedBinding benötigt keine Schema-Eigentümerschaft oder CREATE, aber sie benötigt CONNECT, Schema-USAGE und SELECT auf jeder Tabelle, die von der öffentlichen Website verwendet wird.

Anonyme öffentliche GET- und HEAD-Anfragen können auch Weiterleitungstreffer und 404er aufzeichnen. Um diese Funktionen zu erhalten, benötigt die gecachte Rolle zusätzlich UPDATE auf _emdash_redirects und SELECT, INSERT, UPDATE und DELETE auf _emdash_404_log. Plugins oder Anwendungscode, der während eines öffentlichen GET oder HEAD schreibt, kann mehr erfordern. Verwenden Sie dieselbe Rolle für beide Bindungen, es sei denn, Sie haben die Website mit einer eingeschränkten gecachten Rolle getestet.

Fügen Sie die gecachte Rolle hinzu, nachdem EmDash seine anfänglichen Migrationen abgeschlossen hat. Die Beispiele unten verwenden das optionale emdash-Schema; ersetzen Sie Ihr aktives Schema, wie public. Erstellen Sie das Login und die Datenbankeinstellungen mit der administrativen Rolle Ihres Anbieters:

CREATE ROLE emdash_cached LOGIN PASSWORD 'durch-ein-geheimnis-ersetzen';
GRANT CONNECT ON DATABASE app TO emdash_cached;
ALTER ROLE emdash_cached IN DATABASE app SET search_path = emdash;

Verbinden Sie sich dann als emdash_app, dem Schema- und Tabelleneigentümer, um Zugriff auf bestehende und zukünftige Tabellen zu gewähren:

GRANT USAGE ON SCHEMA emdash TO emdash_cached;
GRANT SELECT ON ALL TABLES IN SCHEMA emdash TO emdash_cached;
GRANT UPDATE ON emdash._emdash_redirects TO emdash_cached;
GRANT SELECT, INSERT, UPDATE, DELETE ON emdash._emdash_404_log TO emdash_cached;

ALTER DEFAULT PRIVILEGES IN SCHEMA emdash
  GRANT SELECT ON TABLES TO emdash_cached;

Verbinden Sie sich mit beiden Rollen und überprüfen Sie, dass sie dasselbe current_database() und current_schema() melden, bevor Sie cachedBinding aktivieren. Bei einem gemeinsamen Schema macht GRANT SELECT ON ALL TABLES auch nicht verwandte Tabellen zugänglich. Gewähren Sie stattdessen Zugriff auf einzelne EmDash-Tabellen und aktualisieren Sie diese Berechtigungen, wenn Sammlungen oder andere Schema-Objekte hinzugefügt werden.

Core-Migrationen

EmDash führt Core-Migrationen standardmäßig automatisch für jeden unterstützten Dialekt aus. Astro Build und Sync erzeugen außerdem eine validierte, geheimnis-freie .emdash/migrations.json, die emdash migrate vor dem Deployment anwenden kann. SQLite, libSQL, PostgreSQL, D1 und die direkte PostgreSQL-Quelle hinter Hyperdrive haben Deployment-Executors.

Siehe Core-Datenbank-Migrationen verwalten für Ziel-Anmeldedaten, CI-Serialisierung, auto/check/manual-Laufzeitrichtlinie und Wiederherstellung nach unbekannten Einträgen oder mehrdeutigen D1-Schreibvorgängen.

Für PostgreSQL laufen Laufzeit-Migrationen über die konfigurierte Verbindung; Hyperdrive-Laufzeit-Migrationen verwenden immer die primäre Bindung. Deployment-verwaltete Hyperdrive-Migrationen verbinden sich direkt mit der PostgreSQL-Quelle. Core-Migrationen können Tabellen, Indizes und Funktionen erstellen, Spalten und Einschränkungen ändern oder löschen und bestehende Zeilen aktualisieren. Eine Rolle, die verbinden und Zeilen ändern kann, aber nicht die bestehenden EmDash-Objekte besitzt, ist nicht ausreichend. Der Einrichtungsassistent kann fehlende Datenbankprivilegien nicht reparieren, da Laufzeit-Migrationen vor der Einrichtung ausgeführt werden.

Wenn die Datenbank leer ist (keine Sammlungen) und der Einrichtungsassistent nicht abgeschlossen wurde, wendet EmDash auch beim ersten Start eine Seed-Datei an. Die Seed-Datei wird aus .emdash/seed.json, dem Pfad in package.json#emdash.seed oder seed/seed.json gelesen — je nachdem, was zuerst gefunden wird — und zur Kompilierzeit in den Build eingebettet. Wenn keine vorhanden ist, wird ein eingebauter Standard-Seed verwendet. Nachfolgende Starts gegen eine bestehende Datenbank lassen deren Inhalt unverändert.

Separate Datenbanken für separate Umgebungen verwenden

Geben Sie Entwicklung, Vorschau, Staging und Produktion jeweils ihre eigene Datenbank. Ein Vorschau-Deployment, das auf die Produktion zeigt, kann Core-Migrationen oder destruktive Inhaltsmodell-Befehle gegen Live-Daten ausführen.

Für Cloudflare definieren Sie jede D1- oder Hyperdrive-Bindung unter der passenden Wrangler-Umgebung und übergeben Sie --env an Wrangler-Befehle. Für Node.js injizieren Sie eine andere Datenbank-URL in jede Laufzeitumgebung. Halten Sie Anmeldedaten in Laufzeit-Geheimnissen, nicht in astro.config.mjs.