İçeriğe atla
Cloudflare Wiki

    gez · aç · Esc kapat

    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üresiYaklaşı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 testiWorkers KV
    Kullanıcıya dönük varlıklar, görseller, veri kümeleri, logR2
    Mevcut PostgreSQL/MySQL’i hızlandırmaHyperdrive
    İşbirliği, global koordinasyon, WebSocket, güçlü tutarlılıkDurable Objects
    İlişkisel veri: profil, ürün, sipariş, müşteriD1

    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
    Terminal — oluşturulan veritabanının kimliği ve wrangler.jsonc'a eklenecek binding bloğu

    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"
    İki komut çıktısı — şema yükleme ve tabloların listelenmesi

    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
    Terminal — migration dosyasının oluşturulması, listelenmesi ve uygulanması
    SELECT * FROM d1_migrations çıktısı — uygulanan migration kayıtları

    Adım 4 — Panelden incele

    Storage & databases → D1 → veritabanı: boyut, tablo listesi ve sorgu konsolu

    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'"
    Komut çıktısındaki meta bloğu — rows_read değerinin tablo satır sayısına eşit olduğu

    Adım 2 — Sorgu planını incele

    EXPLAIN QUERY PLAN sonucu — 'SCAN kullanicilar' satırı

    Adım 3 — Index ekle ve tekrar ölç

    Aynı sorgunun meta bloğu — rows_read değerinin bire düştüğü
    Aynı EXPLAIN çıktısı — bu kez 'SEARCH kullanicilar USING INDEX' satırı

    Adım 4 — Pahalı sorguları bul

    npx wrangler d1 insights urun-veritabani
    En çok satır okuyan sorguların listesi ve okunan/döndürülen oranları

    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>
    Terminal — geri yükleme onayı ve dönen önceki bookmark değeri
    Geri yüklemeden sonra tabloların eski hâline döndüğünü gösteren sorgu çıktısı

    Ölçüm

    ÖlçütIndex’sizIndex’li
    rows_read
    Sorgu süresi
    EXPLAIN sonucuSCANSEARCH
    1 milyon sorguda tahmini maliyet

    Fiyatlandırma

    Rakamlar 1 Eylül 2026’da resmî dokümandan doğrulanmıştır.

    ÜcretsizÜcretli
    Okunan satırGünde 5 milyonAyda ilk 25 milyar dahil, sonrası milyon satır başına 0,001 USD
    Yazılan satırGünde 100.000Ayda ilk 50 milyon dahil, sonrası milyon satır başına 1,00 USD
    Depolama5 GB (toplam)İlk 5 GB dahil, sonrası 0,75 USD / GB-ay

    Egress ücreti yoktur.

    Fatura tuzakları — Cloudflare’in kendi listesi

    DesenNeden pahalı
    Index’siz WHERE kolon = ?Tüm tabloyu tarar
    WHERE a = ? AND b = ?, bileşik index yokTek kolonluk index tam taramayı önler ama yine de o kolonla eşleşen her satırı okur
    Index’siz JOINHer 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 INDEXHer 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ı1050.000
    Veritabanı boyutu500 MB10 GB (artırılamaz)
    Hesap başına depolama5 GB1 TB
    Time Travel süresi7 gün30 gün
    Time Travel geri yükleme10 dakikada 1010 dakikada 10
    Worker çağrısı başına sorgu501.000
    Tablo başına kolon100100
    Satır / BLOB / string boyutu2 MB2 MB
    SQL ifadesi uzunluğu100 KB100 KB
    Bağlı parametre100100
    Sorgu süresi30 saniye30 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_read değerine bak; rows_read / döndürülen satır oranı 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 — uzun IN (?, ?, ...) 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.” Özellikle CREATE INDEX pahalı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 sonucu meta.total_attempts alanı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.

    Hata bildir

    Yanlış bir rakam, eskimiş bir bilgi veya bozuk bir bağlantı mı buldun? Bildir, kaynağıyla birlikte kontrol edelim.