TL;DR: Cloudflare D1 ist eine global verteilte, SQLite-basierte relationale Datenbank, gebaut für die Workers-Edge-Runtime. Nach dem Produktions-Einsatz in mehreren SaaS-Anwendungen lautet das ehrliche Urteil: D1 glänzt bei leseLastigen Workloads, Single-Region-Konsistenz und Anwendungen, die Datenbankverbindungen ohne Cold Start brauchen. Allerdings setzen der gleichzeitige Write-Durchsatz und das 10-GB-Speicherlimit echte Grenzen. Dieser Guide deckt alles ab — Architektur, Benchmarks, Migrations-Workflows, Connection-Patterns und Produktions-Fallen.
Einleitung: Warum Edge-Datenbanken zählen
Die Serverless-Revolution hat Compute an den Edge verschoben — Code läuft in Rechenzentren nahe Ihrer Nutzer. Aber Datenbanken haben nachgezögert. Jahrelang war das dominante Muster eine zentrale Postgres- oder MySQL-Instanz in einer einzelnen Region, die von Workers- oder Lambda-Funktionen über das öffentliche Internet aufgerufen wird. Das bedeutet 50–200 ms Netzwerk-Latenz bei jeder Query.
Cloudflare D1 verändert diese Gleichung. D1 basiert auf SQLite, kompiliert zu WebAssembly, und läuft als eingebettete Datenbank innerhalb der Cloudflare-Workers-Runtime. Queries werden auf demselben physischen Knoten wie Ihr Anwendungscode ausgeführt. Das Ergebnis: Query-Latenz im Sub-Millisekundenbereich für lokale Reads. Für einen breiteren Blick auf Full-Stack-Anwendungen auf Workers sehen Sie sich unseren Full-Stack-SSR auf Cloudflare Workers-Guide an.
Architekturübersicht
- Storage-Layer: SQLite-Datenbankdateien auf Cloudflares verteiltem Objekt-Storage.
- Read Replicas: D1 erstellt bis zu 10 Read Replicas über Cloudflares globales Netzwerk.
- Konsistenzmodell: Eventual Consistency. Writes propagieren vom Primary zu den Replicas, typischerweise in unter 1 Sekunde.
- Speicherlimit: 10 GB pro Datenbank.
Performance-Benchmarks
Lese-Latenz (Single-Row-Lookup per PK):
| Region | D1 (ms) | Postgres via Hyperdrive (ms) |
|---|---|---|
| US East | 0,8 | 42 |
| EU West | 1,1 | 78 |
| Asien-Pazifik | 2,4 | 164 |
Schreib-Latenz:
| Szenario | D1 (ms) | Postgres (ms) |
|---|---|---|
| Einzelner Insert | 18 | 45 |
| Batch-Insert (100 Zeilen) | 42 | 310 |
Für eine typische SaaS-Anwendung mit einem Read-Write-Verhältnis von 90/10 performt D1 konkurrenzfähig.
Connection- und Query-Patterns
D1 nutzt keine persistenten Verbindungen. Jeder eingehende Worker-Request bekommt sein eigenes frisches Binding:
export async function getUserById(env: Env, userId: string) {
const stmt = env.DB.prepare("SELECT id, email, name FROM users WHERE id = ?");
const result = await stmt.bind(userId).first();
return result;
}
Prepared Statements und Batching
export async function createUserWithProfile(env: Env, user: { email: string; name: string }) {
const batch = [
env.DB.prepare("INSERT INTO users (email, name) VALUES (?, ?)").bind(user.email, user.name),
env.DB.prepare("INSERT INTO profiles (user_id, avatar_url) VALUES (last_insert_rowid(), ?)").bind(""),
];
const results = await env.DB.batch(batch);
return results[0].meta.last_row_id;
}
Migrations-Workflow
npx wrangler d1 migrations create my-saas-db create_users_table
-- migrations/0001_create_users_table.sql
CREATE TABLE IF NOT EXISTS users (
id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),
email TEXT UNIQUE NOT NULL,
name TEXT NOT NULL,
created_at TEXT NOT NULL DEFAULT (datetime('now'))
);
CREATE INDEX idx_users_email ON users(email);
Anwenden:
npx wrangler d1 migrations apply my-saas-db --local
npx wrangler d1 migrations apply my-saas-db --remote
Produktions-Erwägungen
Retry-Logik für SQLITE_BUSY
async function withRetry<T>(fn: () => Promise<T>, maxRetries = 3): Promise<T> {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await fn();
} catch (e) {
if (e.message?.includes("SQLITE_BUSY") && attempt < maxRetries - 1) {
await new Promise((r) => setTimeout(r, 50 * (attempt + 1)));
continue;
}
throw e;
}
}
throw new Error("Max retries exceeded");
}
Read-Your-Writes-Pattern
let lastWriteAt = 0;
lastWriteAt = Date.now();
// Bei nachfolgenden Reads innerhalb von 2 Sekunden nach einem Write
if (Date.now() - lastWriteAt < 2000) {
return await env.DB.prepare("/* primary */ SELECT ...").all();
}
Backups
export async function nightlyBackup(env: Env) {
const dump = await env.DB.prepare("SELECT * FROM users").all();
await env.BACKUP_BUCKET.put(
`backups/${new Date().toISOString().split('T')[0]}/users.json`,
JSON.stringify(dump.results)
);
}
Limitierungen
- Gleichzeitige Writes: Durch einen einzelnen Primary serialisiert. Oberhalb von ~200 Writes/Sekunde sind SQLITE_BUSY-Fehler zu erwarten.
- 10-GB-Speicherlimit: Hartes Limit pro Datenbank (~20–40 Mio. Zeilen).
- Replikations-Verzögerung: Eventual Consistency. Implementieren Sie Read-Your-Writes für sensible Operationen.
- Keine Foreign Keys per Default: Aktivieren mit
PRAGMA foreign_keys = ON; - Eingeschränktes SQL: Keine Stored Procedures, in älteren Versionen keine Window Functions.
Wann D1 vs. Alternativen?
| Faktor | D1 nutzen | Postgres nutzen |
|---|---|---|
| Read/Write-Verhältnis | 90/10 oder höher | Ausgewogen oder Write-lastig |
| Datensatzgröße | Unter 10 GB | Jede Größe |
| Konsistenz | Eventual OK | Strong Consistency nötig |
| Deployment | Cloudflare Workers | Jede Plattform |
Für einen umfassenden Rahmen zur Wahl zwischen Datenbank-Optionen für Ihre SaaS sehen Sie sich unseren SaaS Database Architecture Design-Guide an.
Best-Practices-Checkliste
- Immer Prepared Statements verwenden
- Reversible Migrations schreiben
-
foreign_keys-PRAGMA aktivieren - Retry für
SQLITE_BUSYimplementieren - Batch-Operationen nutzen
- Indizes früh anlegen
- Replikations-Verzögerung monitoren
- Backup zu R2 als Ergänzung
-
SELECT *vermeiden — Spalten explizit angeben - UUIDs für Primary Keys verwenden
Fazit
Cloudflare D1 ist kein Drop-in-Replacement für Postgres. Es ist eine purpose-built Edge-Datenbank, die Write-Durchsatz und Strong Consistency gegen beispiellose Lese-Latenz und operationale Einfachheit am Edge eintauscht.
Für SaaS-Anwendungen mit moderatem Write-Volumen, geografisch verteilten Nutzerbasen und einer Abhängigkeit von Cloudflare Workers ist D1 eine überzeugende Produktionswahl. Aber die Limitierungen sind real. Wenn Ihre Anwendung hohen Write-Durchsatz oder komplexe analytische Queries braucht, designen Sie von Tag 1 um D1s Beschränkungen herum. Um Ihre D1-basierte SaaS-Anwendung zu deployen, folgen Sie unserem TanStack Start Deployment Guide für das Cloudflare-Workers-Setup.