如果前一篇文章讓你理解 Workers 如何處理 HTTP 請求,那下一個自然問題就是:資料要放在哪裡?
Cloudflare D1 正是用來回答這個問題的產品。小編先給結論:D1 是 Cloudflare 的 Serverless SQL 資料庫,使用 SQLite 熟悉的 SQL 語意;Worker 透過 Binding 取得資料庫連線,再用準備好的 SQL statement 讀寫資料。
這讓你可以從一個很小的 API 開始,逐步建立具備資料持久性的 Cloudflare 應用程式。
D1 適合處理什麼資料?
D1 適合有表格、欄位、條件查詢與關聯需求的資料,例如:
- 使用者、文章、訂單或留言
- 需要篩選、排序與分頁的資料
- 需要唯一值、索引或外鍵的資料
- Worker API 或管理介面的主要業務資料
可以用一個簡單的方式區分 Cloudflare 的幾種資料服務:
- D1:以列與關聯為主的 SQL 資料
- KV:以 Key-Value 讀取為主的資料
- R2:圖片、影片、備份等物件檔案
這不是在比較誰「比較好」,而是先看資料本身的形狀。若你需要執行 SQL 查詢,D1 才是自然的起點。
先建立 D1 的心智模型
D1 和 Worker 之間不是透過你在程式碼中手動建立的資料庫網路連線來溝通,而是透過 Binding 連接。
這裡有兩個容易混淆的名稱:
- database_name:Cloudflare 上資料庫的名稱,例如 notes-db
- binding:Worker 程式中使用的名稱,例如 DB
當 binding 設定為 DB,程式就會從 env.DB 取得 D1Database 物件。這種設計把部署設定與程式碼分開,也避免把連線資訊硬編碼在原始碼裡。
建立第一個 D1 資料庫
在 Worker 專案中執行:
npx wrangler@latest d1 create notes-dbWrangler 會建立遠端 D1 資料庫,並回傳資料庫 ID 與 Binding 設定。新版流程也可能詢問是否要由 Wrangler 自動把 Binding 加入設定檔;第一次練習時可以選擇讓它代為加入。
如果需要手動設定,Wrangler 設定檔中的 D1 部分大致如下:
{
"d1_databases": [
{
"binding": "DB",
"database_name": "notes-db",
"database_id": "<由 Wrangler 回傳的資料庫 ID>"
}
]
}設定完成後,Worker 就能透過 env.DB 存取這個資料庫。
建立資料表
先建立一個 schema.sql,內容只包含一張簡單的 notes 表:
CREATE TABLE IF NOT EXISTS notes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
);第一次練習建議先在本機資料庫執行:
npx wrangler d1 execute notes-db --local --file=./schema.sql
npx wrangler d1 execute notes-db --local --command="SELECT * FROM notes;"--local 會使用 Wrangler 的本機開發資料庫,不會直接修改部署中的遠端資料庫。若之後要對遠端資料庫執行 SQL,必須明確使用 --remote;實際操作前要先確認目前的資料庫名稱與環境,避免把測試資料寫進正式環境。
讓 Worker 讀寫 D1
下面是一個最小的 TypeScript Worker:
interface Env {
DB: D1Database;
}
export default {
async fetch(request, env): Promise<Response> {
const url = new URL(request.url);
if (request.method === "GET" && url.pathname === "/notes") {
const { results } = await env.DB
.prepare(
"SELECT id, title, created_at FROM notes ORDER BY id DESC",
)
.all();
return Response.json(results);
}
if (request.method === "POST" && url.pathname === "/notes") {
const body = (await request.json()) as { title?: unknown };
const title = typeof body.title === "string" ? body.title.trim() : "";
if (!title) {
return Response.json(
{ error: "title is required" },
{ status: 400 },
);
}
const result = await env.DB
.prepare("INSERT INTO notes (title) VALUES (?)")
.bind(title)
.run();
return Response.json(
{ id: result.meta.last_row_id, title },
{ status: 201 },
);
}
return new Response("Not Found", { status: 404 });
},
};這個 Worker 提供兩個路徑:
- GET /notes:查詢最新的 notes
- POST /notes:接收 title,寫入一筆資料
D1 的使用流程可以拆成三步:
- prepare:準備 SQL statement。
- bind:把外部輸入作為參數傳入。
- all 或 run:執行查詢並取得結果。
這裡使用問號與 bind,而不是把使用者輸入直接串接到 SQL 字串。除了讓程式更容易閱讀,也能避免把未經處理的輸入當成 SQL 語法執行。
範例為了保持短小,省略了 JSON 格式錯誤、錯誤日誌、驗證規則與認證。正式 API 還需要補上這些邊界處理。
本機與遠端環境要分清楚
D1 開發時最容易發生的問題,不是 SQL 寫錯,而是把指令執行在錯的環境。
可以先記住這個區分:
- --local:操作本機 D1,適合開發與測試
- --remote:操作 Cloudflare 上的遠端 D1,會影響部署中的資料
Worker 使用 wrangler dev 執行時,通常會搭配本機 D1。部署後的 Worker 則會使用遠端 Binding。兩者都能叫做 DB,但資料並不是同一份。
因此,建議先在本機建立表格與測試資料,確認 API 行為後,再處理遠端資料庫的 schema 與部署流程。
專案成長後使用 migrations
schema.sql 適合第一次體驗,但正式專案通常要把 schema 變更記錄在版本控制中。D1 提供 migrations,把每次資料庫結構變更保存成有順序的 SQL 檔案。
建立一個 migration:
npx wrangler d1 migrations create notes-db create_notes_table接著把 CREATE TABLE 等 SQL 寫入 migrations 目錄中產生的檔案,再分別套用到本機與遠端環境:
npx wrangler d1 migrations apply notes-db --local
npx wrangler d1 migrations apply notes-db --remote這樣資料庫結構就能和應用程式程式碼一起審查、追蹤與部署。正式環境不要只依賴手動貼到 Dashboard 的 SQL;把結構變更寫成 migration,通常更容易重現與回溯。
什麼時候使用 batch?
如果一次請求需要執行多個 SQL statement,可以考慮 D1Database 的 batch 方法。它能把多個 statement 放進一次資料庫呼叫,減少網路往返;D1 會依序執行這些 statement,並把結果按照原本的順序回傳。
這是進一步改善效能與處理多筆相關變更的工具,但第一次接觸 D1 時,先熟悉單一 prepare、bind 與執行流程即可。
D1 的邊界
D1 讓 Worker 使用 SQL 很方便,但它不代表所有資料庫問題都自動消失。設計時仍要注意:
- 查詢是否有合適的索引
- 資料庫位置與使用者位置是否造成延遲
- API 是否需要認證、授權與輸入驗證
- 讀寫量與查詢複雜度是否符合目前的資料庫選擇
- 本機、預覽與正式環境是否使用正確的資料庫
如果應用需要非常複雜的分析查詢、特定既有資料庫能力,或必須沿用公司現有資料庫,也可以評估其他 Cloudflare 連線與資料服務。D1 的價值在於:對許多 Workers 應用來說,它提供了一個容易開始、又保留 SQL 思維的資料層。
小編建議的練習順序
- 建立 notes 表並用 Wrangler 執行一個 SELECT。
- 讓 Worker 透過 DB Binding 查詢資料。
- 使用 prepare 與 bind 新增一筆資料。
- 把 schema.sql 改成 migration。
- 再加入索引、分頁、認證與錯誤處理。
不要一開始就把 D1、KV、R2 與 Durable Objects 全部放進同一個專案。先讓一個小型 API 正確讀寫一張表,再根據資料形狀與流量需求擴充,通常更容易理解每個 Cloudflare 產品的責任邊界。
結語
Cloudflare D1 可以把熟悉的 SQLite/SQL 開發方式帶進 Workers 應用。它的核心不只是「有一個資料庫可以用」,而是透過 Binding、prepared statement 與 migrations,把執行環境、資料存取與 schema 變更組合成一條清楚的開發流程。
如果你已經完成前一篇的 Workers 入門,現在可以試著把 /health API 改成 /notes,讓回應不再是固定文字,而是來自 D1 的實際資料。
延伸閱讀:



No comments yet