D1
Workers'a bağlanan serverless SQLite veritabanı — sıfıra ölçeklenir, bağlantı yönetimi yoktur.
- DurumGenel kullanımda
- FiyatOkunan satır + yazılan satır + depolama
- Ücretsiz katmanvar
- Doğrulama
D1 nedir?
Bir Worker 330’dan fazla şehirde çalışır; klasik bir ilişkisel veritabanı tek bir bölgede, önünde sunucusuz iş yüklerinin hızla tükettiği bir bağlantı havuzuyla durur.
D1 bu ikilemi ortadan kaldırır. Resmî tanım:
“D1 is Cloudflare’s managed, serverless database with SQLite’s SQL semantics, built-in disaster recovery, and Worker and HTTP API access.”
Bağlantı yönetmezsin, kapasite planlamazsın ve sıfıra ölçeklenir: “You are not billed for hours or capacity units. If you are not running queries against your database, you are not billed for compute.”
Nasıl çalışır?
SQLite temeli
D1 “leverages SQLite’s query engine” ve “compatible with most SQLite’s SQL convention”.
Desteklenen uzantılar: FTS5 (tam metin arama), JSON uzantısı, matematik fonksiyonları
ve bazı PRAGMA ifadeleri.
Her veritabanı bir Durable Object üzerine kuruludur ve tek iş parçacıklıdır:
“Each individual D1 database is inherently single-threaded, and processes queries one at a time.”
Pratik sonuç, Cloudflare’in kendi hesabıyla:
| Ortalama sorgu süresi | Yaklaşık saniyedeki sorgu |
|---|---|
| 1 ms | ~1.000 |
| 100 ms | ~10 |
Hazırlanmış ifadeler ve batch
const stmt = env.DB.prepare("SELECT ad, eposta FROM kullanicilar WHERE kiraci_id = ?1 LIMIT 50");
const { results } = await stmt.bind(kiraciId).all();
Yalnızca sıralı (?NNNN) ve anonim (?) parametreler desteklenir; isimli parametreler henüz yok.
batch() ağ turlarını azaltır ve bir transaction’dır:
“Batched statements are SQL transactions. If a statement in the sequence fails, then an error is returned for that specific statement, and it aborts or rolls back the entire sequence.”
Sessions API ve read replication
Üç oturum biçimi:
| Çağrı | Davranış |
|---|---|
withSession() veya withSession("first-unconstrained") | Herhangi bir instance — en düşük gecikme |
withSession("first-primary") | İlk sorgu birincile gider — en taze |
withSession(bookmark) | Verilen noktadan itibaren devam eder |
Tutarlılık modeli: sequential consistency. Dört garanti sunar: monotonic reads, monotonic writes, writes follow reads, ve read-my-own-writes.
Replica bölgeleri: ENAM, WNAM, WEUR, EEUR, APAC, OC.
Replica gecikmesi için yayımlanmış bir sayısal üst sınır yoktur; doküman yalnızca “a read replica may be arbitrarily out of date” diyor. Güvence bookmark mekanizmasıdır, zaman garantisi değil.
Time Travel
“Time Travel is D1’s approach to backups and point-in-time-recovery, and allows you to restore a database to any minute within the last 30 days.”
Üç özelliği: her zaman açık, ek ücreti yok, bookmark’ları otomatik oluşturur.
Ücretsiz planda 7 gün. Geri yükleme yıkıcıdır ve devam eden sorguları iptal eder — ama işlem önceki bookmark’ı döndürdüğü için yanlış noktaya dönersen geri alabilirsin.
Migration’lar
migrations/ klasöründeki .sql dosyaları; uygulananlar d1_migrations tablosunda tutulur.
Hata durumunda: “this migration will be rolled back, and the previous successful migration will
remain applied.”
Drizzle gibi ORM yerleşimleri için migrations_dir ve migrations_pattern ayarlanabilir.
Yabancı anahtar ihlali doğuracak değişikliklerden önce PRAGMA defer_foreign_keys = true.
Ne zaman kullanılır, ne zaman kullanılmaz
Uygun olduğu işler
- Kullanıcı profilleri, ürün listeleri, siparişler — klasik ilişkisel veri
- Ad-hoc SQL sorgusu gerektiren işler
- Okuma/yazma oranı yüksek uygulamalar (çoğu web uygulaması)
- Kiracı başına veya kullanıcı başına ayrı veritabanı
Uygun olmadığı işler
- Çalışan veri kümesi 10 GB’ı aşıyorsa. Sınır artırılamaz; bölmek gerekir.
- Yazma ağırlıklı veya yüksek eşzamanlı iş yükü. Veritabanı tek iş parçacıklıdır.
- Kesin serileştirilebilirlik veya global sıralama gerekiyorsa. Durable Objects.
- Mevcut PostgreSQL/MySQL varsa veya 1 TB üstü tek veritabanı gerekiyorsa. Hyperdrive.
- Toplu mutasyon. “A single query that attempts to modify hundreds of thousands of rows or hundreds of MBs of data at once will exceed execution limits.” 1.000’er satırlık parçalara böl.
- Tablo başına 100’den fazla kolon gerekiyorsa.
- Etkileşimli transaction gerekiyorsa.
Hangi ürün — Cloudflare’in kendi yönlendirmesi
| İhtiyaç | Ürün |
|---|---|
| Yapılandırma, servis metadata’sı, A/B testi | Workers KV |
| Kullanıcıya dönük varlıklar, görseller, veri kümeleri, log | R2 |
| Mevcut PostgreSQL/MySQL’i hızlandırma | Hyperdrive |
| İşbirliği, global koordinasyon, WebSocket, güçlü tutarlılık | Durable Objects |
| İlişkisel veri: profil, ürün, sipariş, müşteri | D1 |
Somut örnekler
1. Kiracı bazlı sorgu
export default {
async fetch(request, env) {
const kiraci = new URL(request.url).searchParams.get("kiraci");
const { results, meta } = await env.DB
.prepare(`SELECT id, eposta, olusturuldu FROM kullanicilar
WHERE kiraci_id = ?1 ORDER BY olusturuldu DESC LIMIT 50`)
.bind(kiraci)
.all();
// Fatura ölçümü: taranan satır / döndürülen satır oranı
console.log(JSON.stringify({
olay: "sorgu",
okunanSatir: meta.rows_read,
donenSatir: results.length,
oran: meta.rows_read / Math.max(results.length, 1),
}));
return Response.json(results);
},
};
2. Sipariş yazma — batch ile transaction
const siparisEkle = env.DB.prepare(
"INSERT INTO siparisler (siparis_id, musteri_id, durum, tarih) VALUES (?1, ?2, ?3, ?4)");
const kalemEkle = env.DB.prepare(
"INSERT INTO siparis_kalemleri (siparis_id, sku, adet) VALUES (?1, ?2, ?3)");
const stokDus = env.DB.prepare(
"UPDATE stok SET adet = adet - ?2 WHERE sku = ?1 AND adet >= ?2");
// Biri başarısız olursa tamamı geri alınır
const sonuclar = await env.DB.batch([
siparisEkle.bind(siparisId, musteriId, 0, Date.now()),
kalemEkle.bind(siparisId, "SKU-1", 2),
stokDus.bind("SKU-1", 2),
]);
// Her sonucun meta.rows_written değeri tam olarak faturalandığın şeydir
const toplamYazma = sonuclar.reduce((t, s) => t + s.meta.rows_written, 0);
3. Sessions API — kendi yazdığını okuma
export default {
async fetch(request, env) {
// Bookmark'ı istemciden al, yoksa varsayılanla başla
const bookmark = request.headers.get("x-d1-bookmark") ?? "first-unconstrained";
const oturum = env.DB.withSession(bookmark);
// Yazma birincile gider, bookmark ilerler
await oturum.prepare("INSERT INTO goruntulemeler (sayfa, ts) VALUES (?1, ?2)")
.bind("/anasayfa", Date.now()).run();
// Yukarıdaki yazmayı görmesi garanti — read-my-own-writes
const sonuc = await oturum
.prepare("SELECT COUNT(*) AS n FROM goruntulemeler WHERE sayfa = ?1")
.bind("/anasayfa").first();
const yanit = Response.json({ sayi: sonuc?.n });
// Bookmark'ı istemciye geri ver ki sonraki istek devam etsin
yanit.headers.set("x-d1-bookmark", oturum.getBookmark() ?? "");
return yanit;
},
};
4. Index’in faturaya etkisini ölçme
-- Önce planı gör
EXPLAIN QUERY PLAN SELECT * FROM kullanicilar WHERE eposta = 'ali@ornek.com';
-- SCAN kullanicilar → her satır faturalanır
-- SEARCH kullanicilar USING INDEX → yalnızca eşleşenler
CREATE INDEX idx_kullanicilar_eposta ON kullanicilar(eposta);
Çok kolonlu index kuralı: “queries will only use the index if they specify either all of the columns, or a subset of the columns provided all columns to the ‘left’ are also within the query.”
Demo 1: Veritabanı kurma ve migration
Adım 1 — Veritabanı oluştur
npx wrangler d1 create urun-veritabani --location weur
Adım 2 — Şemayı yerelde uygula
npx wrangler d1 execute urun-veritabani --local --file=./schema.sql
npx wrangler d1 execute urun-veritabani --local --command="SELECT name FROM sqlite_master"
Adım 3 — Migration ile ilerle
npx wrangler d1 migrations create urun-veritabani kullanici_tablosu_ekle
npx wrangler d1 migrations list urun-veritabani --remote
npx wrangler d1 migrations apply urun-veritabani --remote
Adım 4 — Panelden incele
Demo 2: Index’in fatura üzerindeki etkisi
Bu demo D1’in en pahalı hatasını somut olarak ölçer.
Adım 1 — Index’siz sorgu çalıştır
npx wrangler d1 execute urun-veritabani --remote \
--command="SELECT * FROM kullanicilar WHERE eposta = 'test@ornek.com'"
Adım 2 — Sorgu planını incele
Adım 3 — Index ekle ve tekrar ölç
Adım 4 — Pahalı sorguları bul
npx wrangler d1 insights urun-veritabani
Adım 5 — Time Travel ile geri dön
npx wrangler d1 time-travel info urun-veritabani
npx wrangler d1 time-travel restore urun-veritabani --timestamp=<UNIX>
Ölçüm
| Ölçüt | Index’siz | Index’li |
|---|---|---|
rows_read | — | — |
| Sorgu süresi | — | — |
EXPLAIN sonucu | SCAN | SEARCH |
| 1 milyon sorguda tahmini maliyet | — | — |
Fiyatlandırma
Rakamlar 1 Eylül 2026’da resmî dokümandan doğrulanmıştır.
| Ücretsiz | Ücretli | |
|---|---|---|
| Okunan satır | Günde 5 milyon | Ayda ilk 25 milyar dahil, sonrası milyon satır başına 0,001 USD |
| Yazılan satır | Günde 100.000 | Ayda ilk 50 milyon dahil, sonrası milyon satır başına 1,00 USD |
| Depolama | 5 GB (toplam) | İlk 5 GB dahil, sonrası 0,75 USD / GB-ay |
Egress ücreti yoktur.
Fatura tuzakları — Cloudflare’in kendi listesi
| Desen | Neden pahalı |
|---|---|
Index’siz WHERE kolon = ? | Tüm tabloyu tarar |
WHERE a = ? AND b = ?, bileşik index yok | Tek kolonluk index tam taramayı önler ama yine de o kolonla eşleşen her satırı okur |
Index’siz JOIN | Her iki tarafı tarar |
| İlişkili alt sorgu | “D1 may evaluate the inner query for each candidate row” |
ORDER BY RANDOM() LIMIT 1 | “D1 must read and sort the entire result set - an index cannot help” |
LIKE '%terim%' | Baştaki % B-tree index’i devre dışı bırakır |
İstek başına CREATE INDEX | Her indekslenen satır için bir yazma |
Ölçüm için her yanıttaki meta bloğuna bak:
"meta": { "duration": 0.204, "rows_read": 5000, "rows_written": 0, "total_attempts": 1 }
Odaklanılacak sorgular: rows_read / döndürülen satır oranı yüksek olanlar.
Limitler
| Özellik | Ücretsiz | Ücretli |
|---|---|---|
| Hesap başına veritabanı | 10 | 50.000 |
| Veritabanı boyutu | 500 MB | 10 GB (artırılamaz) |
| Hesap başına depolama | 5 GB | 1 TB |
| Time Travel süresi | 7 gün | 30 gün |
| Time Travel geri yükleme | 10 dakikada 10 | 10 dakikada 10 |
| Worker çağrısı başına sorgu | 50 | 1.000 |
| Tablo başına kolon | 100 | 100 |
| Satır / BLOB / string boyutu | 2 MB | 2 MB |
| SQL ifadesi uzunluğu | 100 KB | 100 KB |
| Bağlı parametre | 100 | 100 |
| Sorgu süresi | 30 saniye | 30 saniye |
| Worker script başına binding | ~5.000 | ~5.000 |
Eşzamanlı bağlantı: Worker çağrısı başına en fazla 6.
Konum ipuçları: wnam, enam, weur, eeur, apac, oc. Güney Amerika, Afrika ve Orta
Doğu desteklenmiyor — “D1 databases do not run in these locations.”
Lisanslama ve hukuki çerçeve
D1 tescilli bir hizmettir; Cloudflare Hizmet Şartları kapsamındadır.
Veri yerleşimi — D1’in KV’ye göre üstünlüğü. Yargı bölgesi (eu, fedramp) yalnızca
birincil veritabanını değil read replica’ları da kısıtlar:
“If a jurisdiction is configured, read replicas are only created within the jurisdiction set on database creation.”
Bu, KV ile arasındaki önemli bir farktır — KV’de jurisdiction yalnızca kalıcı depolamayı bağlar, cache o sınırın dışına çıkabilir.
Yargı bölgesi oluşturma anında verilir ve sonradan değiştirilemez. Konum ipucuyla birlikte verilirse yargı bölgesi kazanır. Türkiye için tanımlı bir bölge yoktur.
Time Travel ve silme hakkı. 30 günlük geri dönüş penceresi, silinen verinin 30 gün daha geri getirilebilir olduğu anlamına gelir. KVKK kapsamında silme talebi işliyorsan bunu veri envanterine ve süreçlerine yansıtman gerekir.
Sık yapılan hatalar
Faturanın döndürülen satıra göre kesildiğini sanmak. Taranan satıra göre kesilir.
SELECT * çekip filtrelemeyi kodda yapmak. Tam tarama çarpanı.
Bileşik koşula tek kolonluk index koymak. Tam taramayı önler ama yine de o kolonla eşleşen her satır okunur.
ORDER BY RANDOM() LIMIT 1. Büyük tabloda index’le düzeltilemez.
İstek yolunda CREATE INDEX. İndekslenen her satır için bir yazma — en pahalı işlem.
--local bayrağını unutmak (veya tersine, üretime yazmak isterken unutmak).
Replication’ı açıp withSession() çağırmamak. Hiçbir fayda sağlamaz.
Yazmaların otomatik tekrar deneneceğini sanmak. Yalnızca SELECT, EXPLAIN ve WITH
tekrar denenir.
Toplu UPDATE/DELETE’i tek ifadede çalıştırmak. 1.000’er satıra böl.
Time Travel geri yüklemesini güvenli sanmak. Yerinde üzerine yazar ve devam eden sorguları iptal eder.
100 bağlı parametre sınırını aşmak. Uzun IN (?, ?, ...) listelerinde sık karşılaşılır.
Sıkça sorulan sorular
- “Okunan satır” tam olarak ne demek?
- Sorgunun taradığı satır sayısı — döndürdüğü değil. Resmî ifade: “A query that filters on an unindexed column may return fewer rows to your Worker, but is still required to read (scan) more rows to determine which subset to return.” 5.000 satırlık bir tabloda
SELECT * FROM tabloçalıştırmak 5.000 satır okuma sayılır. Tek satır döndüren ama tüm tabloyu tarayan bir sorgu da öyle. D1 faturasındaki sürprizlerin neredeyse tamamı buradan çıkar. - Satır boyutu faturayı etkiler mi?
- Hayır. Resmî ifade: “A row that is 1 KB and a row that is 100 KB both count as one row.” Bu, D1'i R2'den ve KV'den ayıran önemli bir fark — orada boyut önemlidir, burada satır sayısı.
- Index eklemek faturayı düşürür mü?
- Evet, ve bu Cloudflare'in kendi tavsiyesi: “Adding an index so that D1 can jump straight to the rows it needs is therefore one of the most effective ways to reduce both latency and cost.” Ayrıca: “Most unexpectedly large D1 bills come from a small number of frequently run queries that each read (or write) far more rows than they return.” Ölçmek için her yanıttaki
meta.rows_readdeğerine bak;rows_read / döndürülen satıroranı yüksek olan sorgular hedefin. - Read replication GA mi?
- Hayır, public beta — 10 Nisan 2025'ten beri. Bu, Markdown dokümanında görünmeyen bir ayrıntı: beta rozeti yalnızca HTML sayfasında var. Cloudflare'in kendi tavsiyesi: “we recommend trying D1 read replication on a non-production database first.” Karıştırma: D1'in kendisi GA, 1 Nisan 2024'ten beri.
- Replica'lar otomatik mi devreye giriyor?
- Hayır. İki şart var: replication'ı açman ve Sessions API kullanman gerekiyor. Resmî ifade: “To use read replication, you must use the D1 Sessions API, otherwise all queries will continue to be executed only by the primary database.” Replica'lar ek ücret doğurmaz: “You incur the exact same D1 usage billing with or without replicas.”
- Veritabanım 10 GB'ı aşarsa ne olur?
- Aşamaz. Resmî ifade: “the 10 GB limit of a D1 database cannot be further increased.” Tasarım zaten bunu öngörüyor: “D1 is designed for horizontal scale out across multiple, smaller (10 GB) databases, such as per-user, per-tenant or per-entity databases.” Ücretli planda hesap başına 50.000 veritabanı açabilirsin ve ek maliyeti yok — kiracı başına ayrı veritabanı doğal desendir.
- Saniyede kaç sorgu çalıştırabilirim?
- Her D1 veritabanı tek iş parçacıklıdır ve sorguları sırayla işler. Resmî hesap: ortalama sorgun 1 ms sürüyorsa saniyede yaklaşık 1.000, 100 ms sürüyorsa saniyede 10 sorgu. Yazma ağırlıklı veya yüksek eşzamanlılıklı iş yükleri için D1 doğru araç değildir.
- Gerçek transaction var mı?
batch()bir SQL transaction'dır: “If a statement in the sequence fails, then an error is returned for that specific statement, and it aborts or rolls back the entire sequence.” Ama etkileşimli transaction yok — birden çok gidiş-dönüşe yayılan, aralarında uygulama mantığı çalışan bir transaction açamazsın. Buna ihtiyacın varsa Durable Objects'e bak.- Yedekten nasıl dönerim?
- Time Travel her zaman açık ve ücretsiz: “Time Travel is D1's approach to backups and point-in-time-recovery, and allows you to restore a database to any minute within the last 30 days.” Ücretsiz planda 7 gün. Ama geri yükleme yıkıcıdır: “Restoring a database to a specific point-in-time is a destructive operation, and overwrites the database in place.” Devam eden sorgular iptal edilir. İyi haber: geri yükleme önceki bookmark'ı döndürür, yani yanlış noktaya döndüysen geri alabilirsin.
- İsimli parametre kullanabilir miyim?
- Henüz hayır. Resmî ifade: “Currently, D1 only supports Ordered (
?NNNN) and Anonymous (?) parameters. In the future, D1 will support named parameters as well.” Sorgu başına en fazla 100 bağlı parametre var — uzunIN (?, ?, ...)listelerinde bu sınıra dikkat. - Wrangler ve panelden çalıştırdığım sorgular da faturalanıyor mu?
- Evet. Resmî ifade: “any queries you run against your database, including inserting existing data into a new database, table scans (
SELECT * FROM table), or creating indexes count as either reads or writes.” ÖzellikleCREATE INDEXpahalıdır: index kurmak indekslediği her satır için bir yazma üretir ve yazma okumadan 1.000 kat pahalıdır. - Verimi AB'de tutabilir miyim?
- Evet — ve D1'in burada KV'ye göre bir üstünlüğü var. Yargı bölgesi (
eu,fedramp) yalnızca birincil veritabanını değil replica'ları da kısıtlar: “If a jurisdiction is configured, read replicas are only created within the jurisdiction set on database creation.” Yargı bölgesi oluşturma anında verilir ve sonradan değiştirilemez. Türkiye için tanımlı bölge yoktur. - Yazma hatalarında otomatik tekrar deneme var mı?
- Yalnızca okumalarda. Resmî ifade: “Only read-only queries (queries containing only the following SQLite keywords:
SELECT,EXPLAIN,WITH) are retried.” En fazla iki deneme yapılır ve sonucumeta.total_attemptsalanında görürsün. Yazmalar tekrar denenmez — idempotent yazmaları kendi üstel geri çekilmenle sarmalaman gerekir.
İlgili servisler
- WorkersJavaScript/TypeScript/Python kodunu Cloudflare’in 330+ şehirdeki sunucularında, sunucu yönetmeden çalıştırır.
- Workers KVOkuma ağırlıklı, global olarak replike edilen key-value store.
- Durable ObjectsHer nesnenin tek bir instance’ı olan, state tutan compute; sohbet odası, oyun oturumu, sayaç gibi işler için.
- HyperdriveMevcut PostgreSQL/MySQL sunucunu connection pooling ve cache ile Workers’tan hızlı erişilebilir kılar.
- R2S3 uyumlu object storage — çıkış (egress) trafiği ücretsiz.
Bu sayfadaki fiyat ve özellik bilgileri 1 Eylül 2026 tarihinde Cloudflare’in resmî kaynaklarından doğrulanmıştır. Cloudflare fiyatlandırmasını önceden haber vermeden değiştirebilir; bağlayıcı bilgi içinresmî sayfaya bakın.