5. modulAdatbázis II: D1, a natív SQL-adatbázis
Cloudflare for Devs · 5. modul

Adatbázis II: D1, a natív SQL-adatbázis

Az előző modulban láttad, hogyan tartod meg a Postgrest. Most a másik utat nézzük: a D1-et, a Cloudflare beépített SQL-adatbázisát — és főleg azt, hogy neked mikor éri meg, és mikor nem.

5.1Mi a D1 — és mi NEM?

A D1 egy SQLite-alapú, serverless SQL-adatbázis, a platform natív része. Nincs szerver, nincs kapcsolat, nincs connection string: bindingként kötöd a Workerhez, és API-n át kérdezed. Fizetni a ténylegesen olvasott/írt sorok és a tárolt adat után fizetsz — nincs instance-óra, nincs egress díj, és üresjáratban nem kerül semmibe.

A helyes mentális modell: a D1 nem „kis Aurora". Egy adatbázis mérethatára 10 GB, a dialektus SQLite (nem Postgres!), és nincsenek Postgres-extension-ök. Cserébe olyat tud, amit az Aurora nem: egy fiókban több tízezer adatbázisod lehet, ami egészen más architektúrákat nyit meg — például tenantonként egy-egy külön adatbázist, teljes adatszeparációval. Plusz 2025 óta van EU jurisdiction opció: létrehozáskor kikötheted, hogy az adat az EU-ban maradjon (GDPR-hoz kényelmes).

5.2Az API: prepared statements, batch — és a tranzakció-kérdés

wrangler.jsonc
{
  "d1_databases": [
    { "binding": "DB", "database_name": "app-db", "database_id": "<UUID>" }
  ]
}
használat a Workerben / Nuxt server route-ban
// olvasás — prepared statement + bind (SQL injection ellen is)
const { results } = await env.DB
  .prepare("SELECT id, name FROM products WHERE category = ?")
  .bind(category)
  .all();

// egyetlen sor / írás
const user = await env.DB.prepare("SELECT * FROM users WHERE id = ?")
  .bind(id).first();

// batch: több statement EGY hálózati körben — és egyben tranzakció is!
const results = await env.DB.batch([
  env.DB.prepare("INSERT INTO orders (user_id, total) VALUES (?, ?)").bind(uid, total),
  env.DB.prepare("UPDATE inventory SET stock = stock - 1 WHERE sku = ?").bind(sku),
]);
A legnagyobb különbség a Postgres-rutinodhoz képest: a D1-ben nincs interaktív tranzakció — nem tudsz BEGIN-t nyitni, közte alkalmazáslogikát futtatni, majd COMMIT-olni több körben. A tranzakció egysége a batch(): a benne lévő statementek sorban, atomikusan futnak, hiba esetén az egész visszagördül. A „read → döntés kódban → write" mintát így vagy batch-be gyúrod (SQL-oldali feltételekkel, WHERE-ekkel), vagy erős konzisztencia-igénynél Durable Objectbe szervezed (7. modul).

ORM-fronton a Drizzle első osztályú D1-támogatással bír, a Prisma szintén ismeri — a query builder-élmény tehát megmarad, csak a dialektus SQLite.

5.3Migrációk és lokális fejlesztés

A migrációkezelés beépített és szándékosan egyszerű: sorszámozott .sql fájlok, amiket a Wrangler tart nyilván egy meta-táblában:

npx wrangler d1 migrations create app-db add_orders_table
# → migrations/0003_add_orders_table.sql — megírod az SQL-t

npx wrangler d1 migrations apply app-db --local   # lokális SQLite-on (wrangler dev-hez)
npx wrangler d1 migrations apply app-db --remote  # élesben

Drizzle-lel dolgozva a drizzle-kit generate által készített, mappánkénti layoutot a migrations_pattern konfiggal (pl. "migrations/*/migration.sql") közvetlenül eteted a wrangler d1 migrations apply-nak. Lokálisan a D1 egy igazi SQLite-fájl a gépeden (.wrangler/state) — gyors, offline, és nyugodtan törölhető/újraépíthető.

5.4Read replication és a Sessions API

Aurora-világban a read replikákat te konfigurálod, és az appod dönti el, melyik endpointra megy. A D1-nél a Cloudflare automatikusan tart read replikákat több régióban, extra költség nélkül — a te dolgod csak a konzisztencia kezelése, erre való a Sessions API. A lényeg: egy session-ön belül a lekérdezések szekvenciálisan konzisztensek (sosem látsz „visszafelé ugró" adatot), a sessionök közti folytonosságot pedig egy bookmark token biztosítja, amit pl. HTTP headerben adsz körbe:

// a kliens visszaküldi az előző válasz bookmarkját
const bookmark = request.headers.get("x-d1-bookmark") ?? "first-unconstrained";

const session = env.DB.withSession(bookmark);
const result  = await session
  .prepare("SELECT * FROM orders WHERE user_id = ?").bind(uid).run();

// az új bookmarkot visszaadjuk a következő kéréshez
response.headers.set("x-d1-bookmark", session.getBookmark() ?? "");

Ez a minta ismerős lehet: ugyanaz a „read-your-writes egy elosztott rendszerben" probléma, amit Aurora + replikák mellett appszinten oldottál meg — itt API-szinten kapod készen.

5.5Beépített biztonsági háló: Time Travel és export

A D1 minden változást verzióz: a Time Travel funkcióval az adatbázist visszaállíthatod egy múltbeli időpontra (30 napig visszamenőleg a fizetős csomagban) — külön backup-konfiguráció nélkül. Ez az RDS snapshot + point-in-time-restore megfelelője, csak nulla beállítással. Emellett van sima SQL-export (wrangler d1 export) — az adatod nem záródik be.

5.6A döntés: D1 vagy Hyperdrive + Postgres?

Milyen adatbázist használjak? Meglévő Postgres-séma, extension-ök, összetett tranzakciók, >10 GB egyben? Új projekt / önálló feature, mérsékelt adatméret, vagy tenantonkénti izolált DB-k? Hyperdrive + Postgres Aurora marad; minimális kockázat (4. modul) D1 natív, olcsó, nulla üzemeltetés, per-tenant minta igen igen
5. ábra — Az alapdöntés. És fontos: a kettő nem kizáró — sok éles rendszer vegyíti őket.
SzempontHyperdrive + Postgres (Aurora)D1
Dialektus, képességekteljes Postgres: extension-ök, tárolt eljárások, ablakfüggvények mindenestülSQLite: erős alap-SQL, JSON-függvények, FTS — de nincs pgvector, PostGIS & tsai
Tranzakciókteljes értékű, interaktívcsak batch() (atomikus, de nem interaktív)
Méretgyakorlatilag korlátlan10 GB / adatbázis (de tízezernyi DB lehet)
ÜzemeltetésAurora-t továbbra is te fizeted/patcheled/méretezednulla — nincs instance, nincs karbantartási ablak
KöltségmodellAurora instance-óra + tárolás + Hyperdrive (Workers Paid része)olvasott/írt sorok + tárolás; üresjáratban ~0 Ft
Read-skálázásAurora replikák (te konfigurálod)automatikus replikák + Sessions API
Tipikus eset nálada fő, meglévő üzleti adatbázisúj, jól körülhatárolt feature-ök; per-tenant adatok; edge-közeli kiszolgálás
Ajánlott stratégia a te helyzetedben: a fő adatbázis marad Aurora + Hyperdrive — a migráció kockázata így minimális. A D1-et új, jól izolált részeknél vezesd be (pl. egy új mikroszolgáltatás, feature-flag adatok, tenant-specifikus tárak), és ott tanuld meg a batch-alapú tranzakciós mintát. Ha egyszer az Aurora-számla vagy az üzemeltetés fájni kezd, akkor lesz kéznél tapasztalat a nagyobb váltáshoz.

5.7Ellenőrizd magad

  1. Miért nem „kis Aurora" a D1 — mi a két legfontosabb strukturális különbség?
    Válasz

    SQLite-dialektus (nincsenek Postgres-extension-ök, más SQL-felület) és a 10 GB-os per-DB határ — cserébe tízezernyi adatbázis lehet egy fiókban, ami per-tenant architektúrákat tesz természetessé.

  2. Hogyan valósítasz meg „rendelés létrehozása + készlet csökkentése" atomikus műveletet D1-ben interaktív tranzakció nélkül?
    Válasz

    env.DB.batch([...])-ben küldöd a két statementet: egy hálózati kör, sorban, atomikusan futnak — hiba esetén az egész visszagördül. A feltételes logikát SQL-be (WHERE stock > 0) viszed, nem app-kódba a két statement közé.

  3. Mire való a Sessions API bookmark tokenje?
    Válasz

    A sessionök közti logikai folytonosságra: a bookmark rögzíti, „hol tartott" az előző session, így a következő kérés (akár másik PoP-on, másik replikán) garantáltan nem lát régebbi állapotot — read-your-writes konzisztencia elosztott replikák felett.

  4. Mi a D1 megfelelője az RDS point-in-time restore-nak, és mit kellett hozzá konfigurálnod?
    Válasz

    A Time Travel — visszaállítás egy múltbeli időpontra (30 napig, paid). Semmit nem kell konfigurálni, alapból működik.

  5. Mikor rossz döntés a D1 a projektedben?
    Válasz

    Ha a meglévő Postgres-sémád extension-ökre, interaktív tranzakciókra vagy 10 GB-nál nagyobb egybefüggő adatra épül — ilyenkor Hyperdrive + Postgres az út, a D1 erőltetése átírási kockázat valódi haszon nélkül.

Előző4. modul — Adatbázis I: maradó Postgres + Hyperdrive Következő 5b. modul — D1 a gyakorlatban — mélymerülés