· cloudflare / d1 / database

Cloudflare D1 năm 2026: đã sẵn sàng cho production chưa?

D1 đã đạt ngưỡng production-ready cho ứng dụng Workers đọc nhiều năm 2026. Hai giới hạn cứng: ~10 lệnh ghi/giây mỗi database và ép buộc foreign key luôn bật.

Bởi

2.517 từ · 13 phút đọc

D1 là lựa chọn database chính đáng cho các ứng dụng Cloudflare Workers đọc nhiều trong năm 2026. Những cải tiến trong hai năm qua là thực chất: giảm 40–60% độ trễ vào tháng 1/2025, global read replication vào public beta từ tháng 4/2025, và dung lượng tài khoản đạt 1 TB. Nếu ứng dụng của bạn ghi nhiều, phụ thuộc vào multi-writer pattern, hoặc cần tooling migration ORM hoạt động trên môi trường SQLite chuẩn, D1 sẽ làm bạn bực bội trước khi nó phát huy tác dụng — hãy cân nhắc Postgres thay thế.

Bài này dành cho ai

Những developer TypeScript đang build trên Cloudflare Workers, muốn lưu trữ dữ liệu bền vững mà không cần quản lý infrastructure và không rời khỏi Workers ecosystem. Bài review này chỉ đề cập đến path TypeScript Worker — không có REST API, không có Python, không có các trường hợp ngoài stack mà D1 được thiết kế để phục vụ. Nếu bạn chưa dùng Workers, D1 không mang lại gì khác so với một managed database thông thường.

Những gì chúng tôi đã kiểm tra

Bài review này dựa trên tài liệu chính thức của Cloudflare: giới hạn nền tảng D1, release notes, changelog, tài liệu tham chiếu câu lệnh SQL, và tài liệu về foreign key — đối chiếu với changelog Workers SDK và các issue GitHub từ cloudflare/workers-sdk, cloudflare/workerd, và drizzle-team/drizzle-orm. Giá tham khảo từ cloudflare.com, tháng 5/2026.


D1 là gì và phù hợp ở đâu

D1 là một managed SQLite database chạy bên trong mạng của Cloudflare, cùng vị trí với Workers. Mỗi D1 database là một file SQLite duy nhất với một primary node tiếp nhận toàn bộ lệnh ghi. Lệnh đọc được phục vụ từ các bản sao được sao chép không đồng bộ đến các Cloudflare PoP trên toàn cầu.

Đây là mô hình tư duy khác so với các managed database dựa trên Postgres. Hãy hình dung nó như “file SQLite của bạn, có mặt khắp nơi, không cần vận hành” — không phải một relational engine có thể mở rộng theo chiều ngang. Giới hạn ghi là cấu trúc cố hữu, không phải tham số có thể điều chỉnh.

Điểm mạnh cốt lõi là co-location: Worker và D1 database của bạn cùng sống trong một mạng, thường là cùng PoP. Với workload đọc nhiều đang chạy ở edge, điều này loại bỏ round-trip đến một database region riêng biệt. Với workload ghi nhiều, kiến trúc này không thay đổi gì về vị trí của bottleneck. Để so sánh D1 với các edge database khác về latency và tính nhất quán, xem edge database và sự đánh đổi: khi latency là lời nói dối.


Những thay đổi từ khi GA (tháng 4/2024 → tháng 5/2026)

D1 ra mắt chính thức (general availability) vào tháng 4/2024 với global read replication được mô tả là “đang phát triển tích cực.” Hai năm sau, sản phẩm đã cải thiện đáng kể về độ trễ, dung lượng lưu trữ, và khả năng parity giữa môi trường local và production.

Tháng 1/2025: giảm độ trễ 40–60%

Vào ngày 7 tháng 1 năm 2025, Cloudflare loại bỏ các TCP round trip thừa trong đường dẫn D1 Worker API, mang lại mức cải thiện lên đến 60% trên các percentile p50, p90 và p95. Đây là bản sửa lỗi vận hành lớn nhất kể từ khi ra mắt — overhead trước đó đã tạo ra những phàn nàn liên tục trong các thread cộng đồng và thảo luận HN.

Nguồn: Cloudflare changelog, 2025-01-07.

Tháng 4/2025: global read replication (public beta)

Đúng một năm sau GA, read replication chính thức vào public beta. Tính năng này phân phối query đọc đến các PoP gần người dùng. Khi chưa có tính năng này, mọi lệnh đọc đều đi qua primary region — điều đó phần nào triệt tiêu lợi thế co-location của D1 với người dùng phân tán toàn cầu.

Sessions API được ra mắt cùng với read replication. API này dùng Lamport timestamp dạng bookmark để đảm bảo tính nhất quán tuần tự trong một session: sau bất kỳ lệnh ghi nào, tất cả lệnh đọc tiếp theo trong session đó đều được đảm bảo thấy dữ liệu vừa ghi.

Nếu không cấu hình Sessions API, lệnh đọc từ replica có thể trả về dữ liệu cũ mà không có cảnh báo. Các ứng dụng bật read replication mà bỏ qua Sessions API đang đánh đổi tính nhất quán lấy độ trễ thấp hơn — và có thể không nhận ra điều này cho đến khi người dùng báo cáo thấy dữ liệu cũ.

Tài liệu D1 hiện tại không còn ghi chú “beta” cho read replication, nhưng chúng tôi chưa tìm thấy thông báo GA chính thức nào trong các nguồn đã xem xét. Hãy kiểm tra tài liệu hiện tại trước khi coi đây là production-stable cho các workload yêu cầu tuân thủ quy định hoặc tính nhất quán cao.

Nguồn: Read Replication Blog, Read Replication Best Practices.

Tháng 7/2025: dung lượng tài khoản tăng 4 lần

Dung lượng ở cấp tài khoản tăng từ 250 GB lên 1 TB kể từ ngày 1 tháng 7 năm 2025. Giới hạn mỗi database không đổi: 500 MB ở gói Free, 10 GB ở gói trả phí. Mức tăng này chủ yếu có lợi cho các team chạy nhiều D1 database — tài khoản trả phí hỗ trợ đến 50.000 database.

Nguồn: D1 Release Notes.

Tháng 4/2026: khắc phục sự khác biệt foreign key giữa local và remote

Trước tháng 4/2026, Wrangler D1 emulator ở local để foreign key tắt mặc định trong khi D1 remote luôn bật. Sự chênh lệch này khiến các vi phạm FK không bao giờ xuất hiện khi phát triển local có thể phá vỡ production một cách âm thầm. Issue GitHub workers-sdk#5092 đã được đóng vào tháng 4/2026.

Nếu bạn đã chạy D1 project trong môi trường local trước bản sửa lỗi này, hãy kiểm tra lại FK constraints với remote database trước lần migration schema tiếp theo.


Giới hạn và những điều cần lưu ý

Dung lượng và khả năng mở rộng

GóiGiới hạn mỗi DBTổng tài khoảnSố DB tối đa
Free500 MB5 GB10
Trả phí (Workers $5/tháng)10 GB1 TB50.000

Nguồn: D1 Platform Limits.

Gói Free đủ dùng cho hầu hết dự án cá nhân. Giới hạn 10 GB mỗi database ở gói trả phí thoải mái cho giai đoạn đầu, nhưng 10 GB cạn nhanh khi bạn thêm blob metadata, audit log, hoặc full-text search index.

Giới hạn ghi

“D1 databases are inherently single-threaded, and process queries one at a time.” — D1 Platform Limits

Với thời gian query trung bình 100ms, điều này có nghĩa là khoảng 10 lệnh ghi mỗi giây trên mỗi database. Mọi lệnh ghi đều đi qua một primary duy nhất, bất kể read replication có bật hay không. Chính Cloudflare cũng khuyến nghị dùng Durable Objects cho các workload ghi nhiều.

Đây không phải là giới hạn mà Cloudflare có thể giải quyết bằng một configuration flag — đó là bản chất của mô hình file SQLite. Nếu ứng dụng của bạn xử lý comment feed, trạng thái game real-time, event ingestion tần suất cao, hoặc bất kỳ workload ghi có hàng đợi nào, D1 sẽ trở thành bottleneck trước khi bạn đạt đến quy mô người dùng đáng kể.

Mô hình nhất quán dữ liệu

Read replication là opt-in. Sessions API cung cấp tính nhất quán tuần tự cũng là opt-in. Mặc định khi bật read replication là eventual consistency — đọc dữ liệu cũ mà không có cảnh báo.

Cấu hình Sessions API một cách tường minh:

// Luôn tạo session cho các luồng ghi-rồi-đọc
const session = env.DB.withSession('first-primary');

await session.prepare('INSERT INTO events (user_id, type) VALUES (?, ?)').bind(userId, 'login').run();
const user = await session.prepare('SELECT * FROM users WHERE id = ?').bind(userId).first();
// Lệnh đọc này được đảm bảo thấy dữ liệu vừa ghi ở trên

Nếu không dùng session, câu SELECT có thể được phục vụ từ một replica chưa cập nhật lệnh INSERT trên.

Ép buộc foreign key: luôn bật, không có lối thoát

D1 ép buộc foreign key (PRAGMA foreign_keys = ON) trên mọi implicit transaction. PRAGMA foreign_keys = OFF bị bỏ qua âm thầm — D1 không thừa nhận PRAGMA này và cũng không trả về lỗi.

Điều này phá vỡ quy trình migration D1 của Drizzle ORM. Drizzle tạo PRAGMA foreign_keys=OFF ở đầu các file migration để cho phép các thay đổi schema destructive tạm thời vi phạm FK constraints. D1 bỏ qua câu lệnh đó. Nếu một migration vi phạm FK constraint trong quá trình thực thi, D1 báo lỗi và để schema ở trạng thái dở dang.

Các issue GitHub đang theo dõi: drizzle-orm#4212, drizzle-orm#4089.

Cách khắc phục: thêm PRAGMA defer_foreign_keys = ON vào đầu file migration. Điều này trì hoãn việc ép buộc FK đến cuối transaction thay vì giữa chừng câu lệnh. Đây không phải là thay thế hoàn toàn cho việc tắt FK, nhưng nó mở khóa hầu hết các pattern migration của Drizzle cho đến khi ORM này có chế độ migration nhận thức D1.

-- Thêm dòng này vào đầu các migration chạm đến bảng có FK constraints
PRAGMA defer_foreign_keys = ON;

-- SQL migration của bạn tiếp theo sau đây
ALTER TABLE orders DROP COLUMN legacy_id;

Nguồn: D1 Foreign Keys.

Hạn chế về tính năng SQL

D1 chạy query engine của SQLite với một số hạn chế đáng chú ý:

  • Không có explicit transactionBEGIN, COMMITROLLBACK không được hỗ trợ ở cấp SQL; dùng batch API của D1 để đảm bảo tính nguyên tử cho nhiều câu lệnh
  • PRAGMA bị hạn chế — chỉ một tập con được hỗ trợ; các câu lệnh PRAGMA áp dụng theo từng transaction, không theo session
  • Chỉ ba extension — FTS5, JSON và math; các extension SQLite bên thứ ba không khả dụng

Nguồn: D1 SQL Statements.


Đánh giá thực tế

Trường hợp sử dụngPhù hợpLý do
Dự án cá nhân✅ TốtGói Free đủ dùng cho hầu hết dự án cá nhân. Không cần vận hành, co-located với Workers, không có overhead cold-start khi đọc.
Startup nhỏ / SaaS đọc nhiều✅ Tốt, có điều kiện10 GB đủ cho giai đoạn đầu. Read replication + Sessions API cho tốc độ đọc nhanh và nhất quán toàn cầu. Người dùng Drizzle cần workaround defer_foreign_keys cho đến khi ORM thích nghi.
Ghi nhiều / multiplayer / real-time❌ Sai công cụPrimary single-threaded bão hòa ở khoảng 10 lệnh ghi/giây. Chính Cloudflare khuyến nghị Durable Objects cho pattern này.
Enterprise / workload tuân thủ quy định⚠️ Cân nhắc kỹKhông có point-in-time recovery trong tập tính năng được tài liệu hóa. Write availability đi qua một primary duy nhất, không có multi-region failover.

Khi nào nên rời D1

Có ba hướng thường xuất hiện khi các team đụng phải giới hạn của D1.

Option A: Hyperdrive + Postgres

Hyperdrive là connection-pooling proxy của Cloudflare cho các Postgres database bên ngoài. Nó giúp Neon, Supabase hay Railway Postgres hoạt động hiệu quả từ Workers bằng cách pool kết nối và giảm thiểu overhead round-trip. Bạn vẫn ở trên Workers stack và chỉ thay lớp database. Công việc cần làm là migration schema — không cần kiến trúc mới. Một bản ghi thực tế về việc chuyển từ D1 sang Hyperdrive được tài liệu hóa tại mats.coffee/blog/d1-to-hyperdrive. Để chọn Postgres provider phù hợp, xem dịch vụ host Postgres tốt nhất cho SaaS nhỏ.

Option B: Turso

Turso là một edge database tương thích SQLite được xây dựng trên libSQL — một fork của SQLite bổ sung hỗ trợ multi-writer. Migration schema từ D1 sang Turso là phương án đơn giản nhất trong ba lựa chọn: cả hai đều dùng cú pháp SQLite và data model chuyển đổi trực tiếp. Turso hỗ trợ multi-writer topology đúng nghĩa và vượt qua giới hạn ghi single-primary của D1. Một bản ghi về migration quy mô lớn từ D1 sang Turso được tài liệu hóa tại lukasnotes.dk/migrating-large-d1-to-turso. So sánh chi tiết hai tùy chọn xem tại Turso vs Cloudflare D1.

Option C: D1 sharding

Tài khoản trả phí có thể chạy đến 50.000 D1 database. Với các workload đọc nhiều vượt quá giới hạn 10 GB mỗi database, việc chia thành nhiều database và định tuyến ở lớp Worker là một pattern khả thi. Cloudflare xử lý lưu trữ một cách minh bạch; bạn xử lý routing key. Cách này giải quyết vấn đề giới hạn dung lượng nhưng không giúp gì cho giới hạn ghi — sharding theo tenant không tăng write throughput cho mỗi tenant.


Kết luận

D1 là lựa chọn phù hợp cho các ứng dụng TypeScript trên Workers đọc nhiều trong năm 2026, khi bạn muốn không phải lo vận hành infrastructure. Các cải tiến độ trễ tháng 1/2025 đã làm D1 thực sự nhanh; giới hạn 1 TB dung lượng tài khoản loại bỏ lo lắng về scaling cho hầu hết trường hợp; và read replication với Sessions API cho bạn khả năng đọc nhất quán ở edge khi được cấu hình đúng.

Giới hạn ghi và việc ép buộc FK luôn bật mới là những rào cản thực sự — không phải những ngôn từ marketing về “trạng thái beta.” Nếu bạn đang xây dựng thứ gì đó ghi thường xuyên, hoặc team bạn đang chìm trong Drizzle workflow và không thể tiêu hóa thêm ma sát khi migration, D1 sẽ khiến bạn tốn thời gian.

Với developer solo và startup đọc nhiều đã dùng Workers: D1 là điểm khởi đầu đúng đắn. Build trên đó, theo dõi pattern ghi của bạn, và chuyển sang Hyperdrive + Postgres hoặc Turso khi giới hạn xuất hiện.


Tài liệu tham khảo

NguồnURL
D1 Platform Limitshttps://developers.cloudflare.com/d1/platform/limits/
D1 Release Noteshttps://developers.cloudflare.com/d1/platform/release-notes/
D1 SQL Statementshttps://developers.cloudflare.com/d1/sql-api/sql-statements/
D1 Foreign Keyshttps://developers.cloudflare.com/d1/sql-api/foreign-keys/
D1 Read Replication Blog (tháng 4/2025)https://blog.cloudflare.com/d1-read-replication-beta/
D1 Read Replication Best Practiceshttps://developers.cloudflare.com/d1/best-practices/read-replication/
D1 Faster Query Changelog (tháng 1/2025)https://developers.cloudflare.com/changelog/2025-01-07-d1-faster-query/
D1 GA Blog (tháng 4/2024)https://blog.cloudflare.com/building-d1-a-global-database/
workers-sdk#5092 (FK local parity, tháng 4/2026)https://github.com/cloudflare/workers-sdk/issues/5092
workerd#2471 (FK PRAGMA silently ignored)https://github.com/cloudflare/workerd/issues/2471
drizzle-orm#4212 (D1 migration FK conflict)https://github.com/drizzle-team/drizzle-orm/issues/4212
drizzle-orm#4089 (D1 adapter issues)https://github.com/drizzle-team/drizzle-orm/issues/4089
Migration: D1 sang Hyperdrivehttps://mats.coffee/blog/d1-to-hyperdrive
Migration: D1 sang Tursohttps://lukasnotes.dk/migrating-large-d1-to-turso