Design wechseln

Datenbank für Soloselbstständige wählen: D1, Postgres, R2, S3 oder SQLite

Easton editorial illustration: central four-way data-routing hub, structured relational database cylinder, object-storage bucket holding file sheets, single local database disk, sealed backup archive box

"Die offizielle D1-Preisseite erklärt rows read/written, Speicherlimits, den Einfluss von Indizes auf gescannte Zeilen und das Verhalten beim Erreichen des Tageslimits im Free-Tarif."

Im Projekt liegen eine Tabelle users, orders, usage_events, ein Benutzer-Upload unter uploads/2026/06/report.pdf, der Cache cache:daily-stats und lokale Entwicklungsdaten in local-dev.sqlite. Wo soll jedes Objekt liegen? Werden Geschäftsdaten als Dateien im Objektspeicher abgelegt, werden Backups, Abfragen und Exporte schnell umständlich. Fehlen in D1 Indizes auf Filterspalten, verbrauchen rows read das Kontingent rasch; im Paid-Tarif können zusätzliche Kosten entstehen. Die Entscheidung beginnt deshalb bei der Datenart, nicht beim Produktnamen.

Datenzuordnung: Was gehört wohin?

Auch in einem Solo-Projekt benötigen unterschiedliche Objekte unterschiedliche Speicher. Geschäftsfakten brauchen Abfragen, Beziehungen und Zugriffsrechte. Ereignisprotokolle verlangen zuverlässige Schreibvorgänge und bezahlbare Aufbewahrung. Objektdateien brauchen Download-Regeln, Lebenszyklen und ein Kostenmodell für ihren Traffic. Entscheidend ist, ob strukturierte Abfragen und Rechte nötig sind, wie oft zugegriffen wird und wie empfindlich der Workload auf Egress-Kosten reagiert.

Die Tabelle liefert einen praktischen Ausgangspunkt.

Sieben Datenarten und passende Speicher

DatenartKonkrete ObjekteEmpfohlener SpeicherEntscheidungsgrundlage
Geschäftsfaktenusers, orders, Abo-Ansprüche, ZahlungsdatenVorrangig Supabase Postgres, für einfache Fälle D1Strukturierte Abfragen (SELECT/JOIN), Rechte (RLS), tarifgerechte Backups oder Point-in-Time-Restore und Auditierbarkeit
Ereignisprotokolleusage_events, Betriebsaktionen, ZugriffsstatistikenD1 für Edge-Writes oder Postgres für Audit-EreignisseHäufige Writes und einfache Abfragen; normale Analyseereignisse dürfen eine niedrigere Restore-Priorität haben, Sicherheits- und Abrechnungsereignisse nicht
Objektdateienuploads/2026/06/report.pdf, erzeugte Ergebnisse, Exporte, BilderR2 im Cloudflare-Umfeld, S3 in AWS oder Supabase StorageKeine Datenbank-Blobs; R2-Egress, S3-Ökosystem oder Integration mit Supabase Auth/Postgres abwägen
Cachecache:daily-stats, kurzlebiger Zustand, temporäre BerechnungenCloudflare KV, D1 oder lokales SQLiteHäufige Zugriffe und meist lösch- oder rekonstruierbar; KV/D1 am Edge, SQLite lokal
Lokale Entwicklungsdatenlocal-dev.sqlite, Testdaten, Admin-Werkzeug für eine PersonSQLite-DateiEin Benutzer, kein Rechtesystem, leicht kopier- und startbar
Leichte Edge-DatenWorkers-Zähler, Konfigurationstabellen, Domain-ZuordnungenD1 oder Cloudflare KVWorkers-nativer Zugriff, leichte Beziehungen, überwiegend Reads
BackupsDatenbank-Dumps, Export-SnapshotsR2/S3 plus lokale KopieR2-Egress-Modell, S3-Governance und Lifecycle sowie eine unabhängige Kopie für Provider-Ausfälle

Warum Geschäftsfakten meist in Postgres beginnen

Benutzer, Bestellungen, Abo-Ansprüche und Zahlungen sind zentrale Datensätze. Ein Verlust verändert Kundenzugriff und Umsatz. Sie benötigen:

  • Strukturierte Abfragen: Relationale Datenbanken führen SELECT, JOIN, WHERE und ORDER BY aus; Objektspeicher nicht.
  • Zugriffsrechte: Supabase Postgres kann über Row Level Security Client-Zugriffe absichern. D1 bietet derzeit kein natives RLS.
  • Backup und Restore: Supabase Pro, Team und Enterprise erhalten tägliche Backups; PITR ist ein separat aktiviertes kostenpflichtiges Add-on. D1 Time Travel hält 7 Tage in Workers Free und 30 Tage in Workers Paid.
  • Audit-Trails: Trigger und eigene Audit-Tabellen für Änderungen an Zahlungen und Ansprüchen lassen sich in Postgres klar umsetzen.

Supabase Postgres ist keine eingeschränkte Postgres-Abstraktion. Jedes Projekt erhält eine vollständige Postgres-Datenbank, auf der Auth, Storage, Realtime und Edge Functions aufbauen (Supabase-Datenbankdokumentation). Die normalen Postgres-Funktionen bleiben verfügbar.

Ereignisse von Geschäftsdatensätzen trennen

usage_events, Betriebsaktionen und Zugriffsstatistiken verhalten sich anders:

  • Sie werden häufig geschrieben; typische Abfragen filtern Zeiträume oder aggregieren Werte.
  • Nicht auditpflichtige Analysedaten dürfen eine niedrigere Wiederherstellungspriorität haben, brauchen aber eine klare Aufbewahrungs- und Verlustregel. Sicherheits-, Abrechnungs- und Anspruchsereignisse sind keine gewöhnlichen Seitenaufrufe.
  • Häufige Writes verbrauchen rows-written- und Speicherkontingente.

Die Grenze ist konkret:

  • Gehört das Ereignis zu einem Audit-Trail mit user_id und action, nutze Postgres.
  • Ist es nur ein Zähler oder rekonstruierbares Analysesignal, kann D1 oder KV genügen.

Objektdateien nicht in die Datenbank legen

Uploads, erzeugte Ergebnisse, Exportarchive und Bilder gehören nicht in eine Blob-Spalte:

  • Backup-Kosten: Jedes Blob landet im Datenbank-Backup und erhöht Dauer und Speicherbedarf.
  • Abfragelast: Große Objekte in relationalen Zeilen vergrößern Transfer, Cache, Backups und Wartung; breite Abfragen liefern leichter versehentlich Dateiinhalt.
  • CDN-Auslieferung: Objektspeicher lässt sich einfacher mit CDN, Cache-Regeln und signierten Downloads verbinden; Datenbank-Blobs benötigen meist einen Anwendungsproxy.
  • Egress: Blob-Auslieferung verbraucht Datenbank- und Anwendungsbandbreite. Direkte R2-Übertragungen ins Internet haben keine R2-Egress-Gebühr; S3 hängt von Region und Ziel ab.

Die Datenbank speichert nur den Object Key, etwa uploads/2026/06/report.pdf. Die Datei selbst liegt in R2, S3 oder Supabase Storage.

Caches und lokale Entwicklungsdaten

Ein Cache wie cache:daily-stats, kurzlebiger Zustand oder eine temporäre Berechnung hat meist diese Eigenschaften:

  • Häufige Reads und Writes, aber normalerweise Ablauf oder Rekonstruktion möglich. Sicherheitsrelevante Sessions brauchen eigene Regeln für Konsistenz, Ablauf und Widerruf.
  • Rekonstruierbare Cache-Daten gehören gewöhnlich nicht in Backups der Geschäftsdatenbank; Session-Widerrufe und anderer Sicherheitszustand benötigen eine eigene Persistenzstrategie.
  • Zugriffe am Edge sind latenzsensitiv.

Praktische Optionen:

  • Cloudflare KV oder D1 für leichte Edge-Caches in Workers.
  • Eine SQLite-Datei oder In-Memory-Cache in der lokalen Entwicklung.

local-dev.sqlite ist ein Einbenutzerfall ohne Rechtesystem:

  • SQLite ist für lokale Anwendungsdaten und Anwendungsdateien gedacht (Wann SQLite sinnvoll ist).
  • Es löst nicht dasselbe Problem wie eine Client-Server-Datenbank: SQLite betont lokale Einbenutzerdaten, Postgres ein gemeinsam genutztes Mehrbenutzer-Repository.

Leichte Edge-Daten und Backups

D1 oder KV ist ein sinnvoller Start für Workers-Zähler, kleine Konfigurationstabellen und Domain-Zuordnungen:

  • Nativer Zugriff: Worker-Binding oder HTTP API ohne separaten Connection Pool.
  • Leichte Beziehungen: einfaches Schema ohne komplexe JOINs oder großes Foreign-Key-Netz.
  • Read-lastig: deutlich mehr Lese- als Schreibvorgänge.

Backup-Exporte brauchen bezahlbares Abrufen und eine unabhängige Kopie:

  • Für direkte Downloads ins Internet berechnet R2 keine R2-Egress-Gebühr.
  • S3 bietet Object Lock, mehrere Archivklassen und Lifecycle Management.
  • Eine lokale oder bei einem zweiten Provider liegende Kopie schützt vor Konto- und Provider-Ausfällen. Die einzige Restore-Kopie sollte nicht neben der Produktion liegen.

D1: Workers-native Serverless-Datenbank

D1 ist Cloudflares verwaltete Serverless-Datenbank mit SQLite-SQL-Semantik (D1-Überblick). Wichtige Funktionen sind:

  • Time Travel: Wiederherstellung auf jede Minute der letzten 7 Tage in Workers Free oder 30 Tage in Workers Paid. Der Restore überschreibt die Datenbank, daher muss der Zielzeitpunkt stimmen.
  • Read Replication: geringere Leselatenz und mehr Lesedurchsatz für read-lastige Workloads.
  • Workers- und HTTP-API-Zugriff: Binding oder HTTP API ohne eigenen Datenbank-Connection-Pool.
  • Integrierte Disaster Recovery: Cloudflare verwaltet Datenbankhistorie und Wiederherstellungssystem.

Passend für Workers-native und read-lastige Anwendungen

D1 passt zu:

  • Workers- oder Pages-Projekten, die nicht bei jeder Abfrage eine andere Plattform ansprechen wollen.
  • Leichten relationalen Daten wie Konfiguration, Zählern und Domain-Zuordnungen ohne komplexes Beziehungsnetz.
  • Read-lastigen Workloads, deren Reads sich über Replikation skalieren lassen.
  • Projekten, die Workers, R2, KV oder Vectorize bereits nutzen und eine relationale Schicht im selben Ökosystem brauchen.

Weniger passend ist D1 für:

  • Mehrbenutzer-SaaS mit ausgereiftem Rechtesystem und RLS.
  • Bestellungen und Abo-Ansprüche, die ausgereifte Constraints, Audits und getestete Restores verlangen. Postgres ist meist der sicherere Start; das Restore-Fenster hängt vom Managed-Tarif und Add-ons ab.
  • Audit-lastige Systeme, für die Postgres-Trigger und etablierte Audit-Muster benötigt werden.

Rows-read-Abrechnung: gescannte statt zurückgegebene Zeilen

D1 berechnet rows read, rows written und Speicher. Rows read sind die von einer Abfrage gescannten Zeilen, nicht die zurückgegebenen.

Im Juli 2026 nennt die offizielle Preisseite folgende Kontingente und Preise. Vor Veröffentlichung oder größeren Architekturentscheidungen sollten sie erneut geprüft werden.

PositionWorkers FreeWorkers Paid
Rows read5M/TagErste 25B/Monat enthalten
Rows written100K/TagErste 50M/Monat enthalten
Speicher5 GB gesamtErste 5 GB enthalten, danach $0.75/GB-month
Rows-read-MehrverbrauchNicht verfügbar$0.001/million rows read
Rows-written-MehrverbrauchNicht verfügbar$1/million rows written
Egress/BandbreiteKeine gesonderte GebührKeine gesonderte Gebühr

Läuft SELECT * FROM orders WHERE user_id = ? LIMIT 20 auf einer Tabelle mit 50.000 Zeilen ohne Index auf user_id, muss D1 möglicherweise fast die ganze Tabelle lesen, um 20 Zeilen zurückzugeben. Rows read liegen dann näher an 50.000 als an 20.

Ein Filter ohne Index kann also die gesamte Tabelle scannen, obwohl er nur wenige Datensätze zurückgibt. Maßgeblich ist meta.rows_read der tatsächlichen Abfrage, nicht die Ergebniszahl.

Indexdesign und Abfrageeffizienz

So lassen sich rows read kontrollieren:

  1. Lege etwa CREATE INDEX idx_user_id ON orders(user_id); an, damit D1 nur die indizierte Teilmenge scannt. Prüfe den Wert in meta.rows_read.
  2. Frage nur benötigte Spalten ab, um Payload und Kopplung zu reduzieren. D1 zählt jedoch gescannte Zeilen, nicht Spalten; Indizes und Filter senken rows read.
  3. Vergleiche rows_read mit den zurückgegebenen Zeilen. Query-meta und Dashboard zeigen rows read/written, sodass Full-Table-Scans sichtbar werden.

Hinweise für Indizes:

  • Indiziere Spalten in WHERE-Bedingungen wie user_id und created_at.
  • Indiziere JOIN-Schlüssel wie order_id und product_id.
  • Vermeide unnötige Indizes, weil INSERT und UPDATE auch Indexzeilen schreiben können.
  • Prüfe im D1-Dashboard regelmäßig Abfragen mit ungewöhnlich vielen rows read.

D1-Free-Kontingent und Upgrade-Signale

Workers Free begrenzt D1 derzeit auf:

  • 5M rows read pro Tag. Eine Abfrage mit durchschnittlich 50K rows read läuft nur etwa 100-mal bis zum Tageslimit.
  • 100K rows written pro Tag, was write-lastige Anwendungen schnell verbrauchen.
  • 5 GB Gesamtspeicher im Konto.

Workers Paid lohnt sich zu prüfen, wenn:

  • Die täglichen rows read 5M erreichen. Free-Abfragen scheitern danach; Paid enthält monatlich 25B und berechnet Mehrverbrauch.
  • Die täglichen rows written 100K erreichen; Paid enthält monatlich 50M.
  • Mehr als 5 GB benötigt werden; Mehrverbrauch kostet $0.75/GB-month.

D1 ist am stärksten bei leichten relationalen Daten nahe an Workers, nicht als Standard für jeden write-lastigen oder großen Workload. Beobachte rows read, rows written und Speicher.

Supabase Postgres: praktischer BaaS-Standard

Jedes Supabase-Projekt enthält eine vollständige Postgres-Datenbank statt einer eingeschränkten Abstraktion (Supabase-Datenbankdokumentation). Auth, Storage, Realtime und Edge Functions bauen darauf auf; komplexe Abfragen, Foreign Keys, Trigger, Transaktionen, MVCC und Extensions bleiben verfügbar.

RLS für kontrollierten Client-Zugriff

Row Level Security ist ein zentraler Vorteil von Supabase Postgres. Klassisch erreicht nur der Server die Datenbank und Clients verwenden eine API. RLS wendet bei korrekt eingerichteten Policies und Schlüsseln Rechte auf einzelne Zeilen einer Client-Abfrage an.

RLS unterstützt:

  • Zugriffskontrolle: Eine Policy kann nur Zeilen zeigen, deren user_id zum angemeldeten Benutzer passt.
  • Audit-Design: RLS definiert die Zugriffsgrenze; eine Audit-Tabelle, Trigger oder Logging zeichnen gesondert auf, wer wann was getan hat.
  • Weniger doppelte Rechteprüfung: Regeln können in der Datenbank liegen, während der Server weiterhin Identitäten prüft, privilegierte Schlüssel schützt und erhöhte Operationen kontrolliert.

Das passt zu Geschäftsfakten, rechteintensiven Anwendungen, Mehrbenutzer-SaaS, Bestellungen und Abo-Ansprüchen. RLS ist die Datenbankgrenze, ersetzt aber weder Schema- noch Audit-Design.

Backups und Wiederherstellung

Im Juli 2026 nennt Supabase offiziell:

PositionFreeProTeam
Datenbankgröße500 MB pro Projekt enthalten8 GB pro Projekt, danach Mehrverbrauch8 GB pro Projekt, danach Mehrverbrauch
Preis$0$25/Monat$599/Monat
Automatische BackupsNicht enthaltenTäglich, 7 Tage AufbewahrungTäglich, 14 Tage Aufbewahrung
PITRNicht enthaltenBezahltes Add-on, etwa $100/Monat für 7 TageBezahltes Add-on, etwa $100/Monat für 7 Tage

Daraus folgen drei praktische Punkte:

  • Ein Free-Projekt darf Plattform-Backups nicht als Restore-Plan betrachten. Führe supabase db dump oder pg_dump regelmäßig aus und bewahre eine externe Kopie auf.
  • Pro und Team erhalten tägliche Backups, können aber Änderungen seit dem letzten Backup verlieren.
  • PITR ist in Pro nicht standardmäßig enthalten. Es benötigt mindestens Small Compute und wird für 7, 14 oder 28 Tage separat berechnet.

Nicht nur die Datenbankgröße entscheidet über ein Upgrade. Für Bestellungen und Ansprüche müssen zuerst Recovery Point Objective, Recovery Time Objective und Häufigkeit der Restore-Tests feststehen. Danach lässt sich zwischen täglichen Backups und PITR entscheiden.

D1 und Supabase: Rechte und Wiederherstellung

DimensionD1Supabase Postgres
PositionierungWorkers-native Serverless-DatenbankVerwaltetes Postgres-BaaS
ZugriffskontrolleKein natives RLSRLS kann Client-Abfragen absichern
WiederherstellungTime Travel: Free 7 Tage, Paid 30 TageTägliche Backups für Pro/Team/Enterprise; PITR als Add-on
Passender EinsatzLeichte relationale Daten in WorkersGeschäftsfakten, Mehrbenutzer-SaaS, Bestellungen, Ansprüche
AbrechnungRows read/written plus SpeicherDatenbankspeicher, Compute und Tarifnutzung

Beide lassen sich kombinieren:

  • D1 speichert read-lastige Edge-Konfiguration, Zähler und Domain-Zuordnungen.
  • Supabase Postgres speichert Benutzer, Bestellungen, Abo-Ansprüche und Zahlungen.

Ein SaaS-Tool kann Konfiguration und Zähler in D1 halten, während Postgres Benutzer und Ansprüche besitzt. D1 bleibt nahe an Workers; Postgres liefert ausgereifte Rechte, Constraints und Restore-Optionen.

R2: Objektspeicher ohne R2-Egress-Gebühr

R2 ist Cloudflares S3-kompatibler Objektspeicher. Direkte Übertragungen aus R2 über Workers API, S3 API oder r2.dev ins Internet verursachen keine R2-Egress-Gebühr (R2-Preise); ein verbundener kostenpflichtiger Dienst kann dennoch abrechnen. R2 passt zu Uploads, erzeugten Ergebnissen und Exporten, aber kostenloser Egress macht Speicher und Operationen nicht kostenlos.

Abrechnung der Class-A/B-Operationen

R2 berechnet Speicher, Class-A- und Class-B-Operationen. Infrequent Access hat zusätzlich Retrieval-Gebühren.

Im Juli 2026 gelten laut Preisseite:

PositionFree-KontingentStandardInfrequent Access
Speicher10 GB-month/Monat$0.015/GB-month$0.01/GB-month
Class-A-Operationen1M/Monat$4.50/million$9.00/million
Class-B-Operationen10M/Monat$0.36/million$0.90/million
DatenabrufKeinerKeiner$0.01/GB
Internet-EgressKostenlosKostenlosKostenlos
MindestdauerKeineKeine30 Tage

Zu den Klassen gehören:

  • Class A, die teurere Gruppe: PutObject, CopyObject, ListObjects und Lifecycle-Tier-Wechsel. Writes und Listings fallen meist hierunter.
  • Class B, die günstigere Gruppe: GetObject, HeadObject und HeadBucket. Reads fallen meist hierunter.
  • Kostenlose Operationen: DeleteObject, DeleteBucket und AbortMultipartUpload.

Was das R2-Free-Kontingent nicht bedeutet

10 GB-month sind kein unbegrenzter Speicher:

  • Speicher: 10 GB-month misst Kapazität über den Abrechnungszeitraum, nicht Traffic. Mehr Daten erfordern bezahlte Nutzung oder Bereinigung.
  • Class A: 1M Operationen pro Monat reichen für viele kleine Seiten, Batch-Uploads können das Kontingent aber schnell verbrauchen.
  • Class B: 10M Operationen pro Monat decken viel Leseverkehr ab, ein stark besuchter Bild-Origin kann sie überschreiten.

Infrequent Access hat eine Mindestdauer von 30 Tagen. Früheres Löschen vermeidet die Mindestgebühr nicht. Die Klasse passt zu Backups und langlebigen Objekten, nicht zu temporären Ergebnissen.

Passend für Uploads und erzeugte Ergebnisse

R2 passt zu:

  • Benutzer-Uploads wie uploads/2026/06/report.pdf, Bildern und Dokumenten, besonders bei häufigen Downloads.
  • Erzeugten Reports, Exporten und Bildverarbeitungsergebnissen.
  • Datenbank-Dumps und Snapshots, die günstig abrufbar sein sollen.
  • Projekten mit Workers, D1, KV oder Vectorize.

Nicht geeignet ist R2 für:

  • Geschäftsfakten wie Benutzer und Bestellungen, die strukturierte Abfragen und Rechte benötigen.
  • Workloads mit S3 Object Lock, mehr Speicherklassen oder AWS-nativer Bucket- und Regionsreplikation.

R2 und S3 im Vergleich

DimensionR2S3
Internet-EgressAuf R2-Seite kostenlos; verbundene Dienste können abrechnenAbhängig von Region, Ziel und Nutzung; aktuelle AWS-Preise prüfen
Speicher$0.015/GB-month für StandardMehrere Klassen einschließlich Standard und Glacier
ÖkosystemNativ in Workers und PagesTiefe AWS-Integration einschließlich Lambda
GovernanceLifecycle-Regeln, Standard/IA und Queue-EventsObject Lock, mehrere Glacier-Klassen, Lifecycle, Replication und mehrere Event-Ziele
Passender EinsatzCloudflare-Ökosystem und egress-sensitive AuslieferungAWS-Ökosystem, Governance, Data Lakes und Unternehmensanwendungen

R2 wählen, wenn:

  • Downloads Egress-Kosten zu einem wesentlichen Faktor machen.
  • Die Anwendung bereits auf Workers oder Pages läuft.

S3 wählen, wenn:

  • Lambda-, Data-Lake- oder Unternehmensworkflows von AWS-Diensten abhängen.
  • Object Lock, mehr Glacier-Klassen, regionsübergreifende Replikation oder AWS-IAM-Governance benötigt werden.
  • Das breitere AWS-Werkzeugset mit CloudWatch, IAM und Batch Operations wertvoll ist.

R2 und S3 sind keine vollständigen Ersatzprodukte. Eine Cloudflare-Anwendung kann CDN-Dateien und erzeugte Ergebnisse in R2 halten, governance-relevante Archive dagegen in S3.

S3: AWS-Ökosystem und Governance

Amazon S3 ist ein Objektspeicherdienst für Data Lakes, Websites, mobile Anwendungen, Backup und Restore, Archive, Unternehmensanwendungen, IoT und Analytics (Amazon S3 User Guide). Er bietet:

  • Speicherklassen wie Standard, Intelligent-Tiering, Glacier und Glacier Deep Archive.
  • Lifecycle-Regeln zum automatischen Verschieben oder Löschen.
  • Object Lock mit WORM-Aufbewahrung gegen Überschreiben und Löschen.
  • Same-Region- und Cross-Region-Replication für Restore, Latenz und Governance.
  • IAM- und Bucket-Policies plus Block Public Access.
  • Event Notifications für Lambda und andere AWS-Ziele.

Passend für AWS-Integration und Governance

S3 passt zu:

  • Produkten, die Lambda, EC2, RDS oder DynamoDB bereits nutzen.
  • Anforderungen an Object Lock, Archivklassen und formelle Aufbewahrung.
  • Data Lakes und IoT-Pipelines mit AWS-Analysediensten.
  • Langfristigen Backup-, Restore- und Archivabläufen mit Lifecycle-Regeln.

Weniger passend ist S3, wenn:

  • Häufige Benutzer-Downloads Egress-Kosten empfindlich machen; maßgeblich sind aktuelle AWS-Preise für Region, Ziel, Cache und Volumen.
  • Die Anwendung sonst Cloudflare-nativ ist und direkt aus Workers oder Pages auf R2 zugreift.

S3 und R2: Tiefe von Ökosystem und Governance

S3s Vorteil liegt in der Breite seiner AWS-Integrationen und Governance-Funktionen:

  • Event-Ziele: S3 Event Notifications senden an SNS, SQS, Lambda und EventBridge. R2 kann Object-Create- und Object-Delete-Ereignisse an Cloudflare Queues senden, die Worker oder HTTP-Pull verarbeiten.
  • Speicherklassen: S3 bietet mehrere Glacier-Archivklassen; R2 konzentriert sich derzeit auf Standard und Infrequent Access.
  • Object Lock: WORM-Aufbewahrung verhindert Überschreiben oder Löschen während der Frist.
  • Replication: S3 kopiert Objekte, Metadaten und Tags in Buckets derselben oder einer anderen Region.

S3 wählen, wenn:

  • Lambda, Data Lakes oder Unternehmensanwendungen von AWS-Integrationen abhängen.
  • Object Lock, Glacier-Klassen oder Lifecycle-Governance nötig sind.
  • Langzeitarchive von der Glacier-Familie profitieren.

R2 wählen, wenn:

  • Benutzer-Uploads und erzeugte Dateien häufig heruntergeladen werden.
  • Workers und Pages die primäre Laufzeit sind.

Eine kombinierte Architektur kann CDN-Dateien und Ergebnisse in R2, governance-relevante Backups in S3 halten. Datenart und Zugriffsmuster entscheiden, nicht eine Ein-Provider-Regel.

SQLite: lokal und eingebettet zuerst

SQLite passt zu lokalen Anwendungsdaten, Anwendungsdateien, Websites mit geringem bis mittlerem Traffic, Analysen und Caches (Wann SQLite sinnvoll ist). Es konkurriert nicht direkt mit Client-Server-SQL-Datenbanken. Diese betonen ein gemeinsames Repository, Parallelität, Zentralisierung und Kontrolle; SQLite betont lokale Einbenutzerdaten in einer kopierbaren Datei.

Passend für Einbenutzer-Werkzeuge und lokale Backends

SQLite passt zu:

  • Einbenutzer-Werkzeugen, lokalen Dashboards, Analyseprogrammen, kleinen Spielen und Einzeldatei-Datensätzen.
  • Anwendungsdateiformaten für CAD-, Finanz- oder Medienverwaltungssoftware.
  • Websites mit geringem bis mittlerem Traffic. SQLite nennt weniger als 100K Hits pro Tag als meist unproblematisch, doch das ist eine konservative Beobachtung und keine Leistungszusage. Hardware, Abfragekomplexität und parallele Writes bestimmen die Kapazität.
  • Lokalen Entwicklungsdaten wie local-dev.sqlite.
  • Caches und temporären Berechnungen ohne dauerhaft gemeinsam genutzten Zustand.

Weniger passend ist SQLite für:

  • Mehrbenutzer-SaaS mit Rechten, parallelen Writes und Audit-Anforderungen.
  • Bestellungen und Abo-Ansprüche, die ausgereifte Backups und Point-in-Time-Recovery brauchen.
  • Write-lastige Parallelität, weil SQLite zwar viele Leser, aber jeweils nur einen Schreiber erlaubt.

SQLite und Postgres: Migrationssignale

DimensionSQLitePostgres
PositionierungLokale Daten und AnwendungsdateiGemeinsames Client-Server-Repository
Passender EinsatzEinbenutzer-Werkzeuge, kleine Spiele, lokale DashboardsMehrbenutzer-SaaS, Bestellungen, Abo-Ansprüche
ParallelitätEin Schreiber, viele LeserMehrere Schreiber mit MVCC
RechteKeine eingebaute BenutzerverwaltungRLS und Benutzer-/Rollenverwaltung
KostenKein separater DatenbankserverAbhängig von Self-Hosting oder Managed-Tarif, Compute und Backups

Von SQLite zu Postgres wechseln, wenn:

  1. Aus einem Einbenutzer-Werkzeug ein Mehrbenutzer-SaaS mit Rechtesystem wird.
  2. Mehrere Benutzer oder Instanzen denselben Zustand gleichzeitig ändern müssen.
  3. Zahlungen Bestellungen und Ansprüche einführen, die Audit und getesteten Restore brauchen.
  4. Ein Modell aus users/roles/permissions Datenbankrechte benötigt.

Ein persönliches Analyse-Dashboard kann bei SQLite bleiben. Teilen mehrere zahlende Kunden denselben Dienst, ist Postgres meist die klarere Grenze.

SQLite ersetzt Postgres nicht

Auch SQLite selbst beschreibt sich nicht als Ersatz für eine Client-Server-SQL-Datenbank:

  • SQLite optimiert lokale Einbenutzer-Einfachheit und eine als Datei kopierbare Datenbank.
  • Postgres optimiert ein gemeinsam genutztes Mehrbenutzer-Repository mit parallelen Zustandsänderungen und zahlungskritischen Datensätzen.

SQLite benötigt keinen separaten Datenbankserver. Postgres-Kosten hängen von Self-Hosting oder Managed-Tarif, Compute, Speicher und Backups ab. Beide brauchen einen getesteten Restore-Prozess.

SQLite wählen für:

  • Lokale Werkzeuge und kleine Spiele ohne Zahlungen oder Rechtesystem.
  • Entwicklungsfixtures und temporäre Daten.
  • Persönliche Websites und Dokumentationswerkzeuge mit wenigen parallelen Writes.

Postgres wählen für:

  • Mehrbenutzer-SaaS mit Bestellungen, Abos und Rechten.
  • Auditierbare Betriebs- und Anspruchsänderungen.
  • Geschäftsdaten mit konfigurierbarer Point-in-Time-Recovery.

Beide können koexistieren: SQLite für lokale Entwicklung oder rekonstruierbare Caches, Postgres für produktive Geschäftsfakten.

Drei typische Fehler

Die häufigsten Fehler sind Geschäftsfakten als Objekte, ignorierte scanbasierte D1-Abrechnung und die Annahme eines unbegrenzten R2-Free-Kontingents. Sie erschweren Restores, verlangsamen Abfragen und machen Kosten unvorhersehbar.

Fehler 1: Geschäftsfakten im Objektspeicher

Tabellen wie users, orders und auditpflichtige usage_events gehören nicht in R2 oder S3. Objektspeicher bietet keine relationalen Abfragen, Constraints, zeilenbezogenen Rechte oder Datenbank-Audit-Muster.

Die Folgen sind konkret:

  • Kein SELECT oder JOIN: Objektspeicher ist key-basiert. Für SELECT * FROM orders WHERE user_id = ? LIMIT 20 müsste die Anwendung Bestellobjekte selbst auflisten und herunterladen.
  • Umständlicher Restore: Eine Dateisammlung ist keine transaktionale Bestellhistorie. SQL-Dump oder verwaltete Point-in-Time-Systeme liefern einen kohärenteren Datenbank-Restore.
  • Langsame Exporte: Datenbankabfragen streamen passende Datensätze; ein Objekt pro Bestellung kann das Scannen vieler Dateien erfordern.

Geschäftsfakten bleiben in der Datenbank, Dateien im Objektspeicher. Die Datenbank speichert einen stabilen Object Key; R2, S3 oder Supabase Storage enthält die Datei.

Fehler 2: Rows-read-Abrechnung übersehen

D1 zählt gescannte statt zurückgegebene Zeilen. Ein Filter ohne Index kann daher viel mehr rows read verbrauchen als die Ergebniszahl vermuten lässt.

Bei 50.000 orders-Zeilen kann SELECT * FROM orders WHERE user_id = ? LIMIT 20 ohne Index viele Zeilen scannen. Den abrechenbaren Wert zeigt meta.rows_read. Free-Abfragen scheitern nach 5M pro Tag; Paid berechnet Nutzung über dem monatlichen Kontingent.

Die Korrektur:

  1. Indiziere die reale Filterspalte, etwa mit CREATE INDEX idx_user_id ON orders(user_id);.
  2. Prüfe mit EXPLAIN QUERY PLAN und meta.rows_read, ob ein Full-Table-Scan bleibt.
  3. Wähle nur benötigte Spalten für eine kleinere Payload, ohne zu vergessen, dass D1 Zeilen statt Spalten zählt.

Fehler 3: Das R2-Free-Kontingent für unbegrenzt halten

R2 Free enthält derzeit 10 GB-month Standard Storage, 1M Class-A- und 10M Class-B-Operationen pro Monat. Das sind Kontingente, keine unbegrenzte Nutzung.

Häufige Missverständnisse:

  • 10 GB-month misst gespeicherte Kapazität über Zeit, nicht Transfer.
  • PutObject ist eine Class-A-Operation. Batch-Erzeugung kann das Monatskontingent trotz kleiner Gesamtdatenmenge verbrauchen.
  • Infrequent Access hat eine Mindestdauer von 30 Tagen; früheres Löschen verursacht trotzdem die Mindestgebühr.

Überwache Speicher und Operationszahlen, lasse alte Ergebnisse bewusst ablaufen und verwende Infrequent Access nicht für temporäre Dateien. Lokales SQLite oder ein Cache kann für kurzlebige Daten besser passen.

Fazit

Der Datentyp entscheidet: Geschäftsfakten, Ereignisse, Objekte, Caches, lokale Entwicklungsdaten, leichte Edge-Daten und Backups. Supabase Postgres besitzt meist die Geschäftsfakten, weil es relationale Constraints, RLS, konfigurierbare Restores und Audit-Muster bietet. D1 passt zu leichten Workers-nativen relationalen Daten, R2 oder S3 zu Objekten und SQLite zu lokalen Einbenutzerdaten.

Drei Maßnahmen machen die erste Version sicherer:

  1. Klassifiziere jedes Objekt und notiere Abfragen, Rechte, Zugriffshäufigkeit und Kostenanforderungen.
  2. Indiziere D1-Filterspalten und überprüfe das Ergebnis anhand der Rows-read-Metriken.
  3. Halte Geschäftsdaten aus dem Objektspeicher, vermeide unindizierte Scans und schätze das gesamte R2-Kontingent statt nur den Speicher.

Die nächsten Beiträge behandeln Zahlungen und Benutzersysteme. Diese Themen bestätigen die Grenze: Zahlungsbestellungen brauchen Postgres-Constraints, Backups und Audits; Benutzeransprüche und Rechte benötigen RLS und getestete Wiederherstellung.

Ist der Speicherort eines Objekts weiterhin unklar, helfen die Zuordnungstabelle und die früheren Serienbeiträge zu Architekturprinzipien, Backend-Stack und Deployment. Erst die Systemgrenze festlegen, dann die Speicherrolle verfeinern.

Speicher für ein Solo-Projekt zuordnen

Trenne in sechs Schritten von der Bestandsaufnahme bis zum Wiederherstellungstest die Aufgaben von Datenbank und Objektspeicher.

  1. 1

    Step 1: Datenobjekte erfassen

    Liste users, orders, usage_events, uploads, Caches, lokale Dateien und Backups auf, ohne sie zuerst nach Produkten zu gruppieren.
  2. 2

    Step 2: Objekte klassifizieren

    Kennzeichne jedes Element als Geschäftsfakt, Ereignis, Objektdatei, Cache, lokale Daten oder Backup und notiere, ob es ablaufen oder neu erzeugt werden darf.
  3. 3

    Step 3: Konsistenz und Rechte festlegen

    Erfasse Anforderungen an Transaktionen, Constraints, RLS, parallele Schreibzugriffe, Audits und mehrere Instanzen, um zwischen Postgres und D1 zu entscheiden.
  4. 4

    Step 4: Zugriffe und Kostentreiber schätzen

    Schätze D1 rows read/written, R2 Class A/B operations, Objektvolumen, Lesehäufigkeit und mögliche Egress-Kosten.
  5. 5

    Step 5: Stabile Referenzen entwerfen

    Speichere Object Key, Eigentümer, Status und Metadaten in der Datenbank, den Dateiinhalt im Objektspeicher und halte die Key-Namen stabil.
  6. 6

    Step 6: Backup und Migration prüfen

    Richte Exporte, externe Kopien, Löschfristen und Restore-Tests ein; migriere zuerst Metadaten, dann Objekte und zuletzt den Lesepfad.

FAQ

Sollte ein Solo-Projekt mit D1 oder Supabase Postgres beginnen?
Für einfache, leselastige relationale Daten in Workers oder Pages kann D1 passen. Benutzer, Bestellungen, Abos, Berechtigungen und komplexe Abfragen gehören meist in Supabase Postgres.
Welche Daten gehören in R2 oder S3?
Beide eignen sich für Bilder, PDFs, Exporte, Backups und erzeugte Ergebnisse. Die Datenbank speichert Metadaten, Eigentümer, Status und Object Key statt großer Dateiinhalte.
Kann SQLite das erste SaaS-Produkt betreiben?
Für Werkzeuge auf einem Rechner und wenig konkurrierende Schreibzugriffe kann SQLite genügen. Gemeinsamer Zustand mehrerer Instanzen, komplexe Rechte, Zahlungsansprüche oder viele parallele Writes sprechen für Postgres.
Dürfen Benutzer-Uploads in die Datenbank?
Meist nicht. Lege Dateiinhalte in R2, S3 oder Supabase Storage und Referenzen samt Zugriffsregeln in die Datenbank, damit Backups, Downloads, CDN und Löschregeln beherrschbar bleiben.
Was bedeutet die Abrechnung von D1 rows read?
Gezählt werden gescannte, nicht zurückgegebene Zeilen. Ein Filter ohne Index kann wenige Ergebnisse liefern und viele Zeilen lesen; prüfe Indizes, EXPLAIN QUERY PLAN und meta.rows_read.
Reicht das kostenlose Kontingent von Cloudflare R2?
Schätze Standard Storage, Class A/B operations und Lesehäufigkeit gemeinsam. Aktuell sind 10 GB-month, 1M Class-A- und 10M Class-B-Anfragen pro Monat enthalten; Preise können sich ändern und das Kontingent gilt nicht für Infrequent Access.

17 Min. Lesezeit · Veröffentlicht am: 9. Okt. 2026

Kommentare

Melde dich mit GitHub an, um einen Kommentar zu hinterlassen

Easton BlogEaston Blog