What is Cloudflare D1?
Cloudflare D1 is a serverless SQL database built on SQLite, running at Cloudflare's edge network. Your database is milliseconds from your users — everywhere in the world.
Free tier: 5 GB storage, 5M reads/day, 100K writes/day.
Quick Start
npm install -g wrangler
wrangler login
# Create database
wrangler d1 create my-db
# Run SQL
wrangler d1 execute my-db --command "CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT UNIQUE)"
Use in Workers
// src/index.ts
export default {
async fetch(request: Request, env: Env) {
const url = new URL(request.url);
if (url.pathname === "/users" && request.method === "GET") {
const { results } = await env.DB.prepare(
"SELECT * FROM users ORDER BY id DESC LIMIT 20"
).all();
return Response.json(results);
}
if (url.pathname === "/users" && request.method === "POST") {
const { name, email } = await request.json();
const result = await env.DB.prepare(
"INSERT INTO users (name, email) VALUES (?, ?) RETURNING *"
).bind(name, email).first();
return Response.json(result, { status: 201 });
}
if (url.pathname.startsWith("/users/") && request.method === "GET") {
const id = url.pathname.split("/")[2];
const user = await env.DB.prepare(
"SELECT * FROM users WHERE id = ?"
).bind(id).first();
if (!user) return new Response("Not found", { status: 404 });
return Response.json(user);
}
return new Response("Not found", { status: 404 });
},
};
Configuration
# wrangler.toml
name = "my-api"
main = "src/index.ts"
compatibility_date = "2026-03-01"
[[d1_databases]]
binding = "DB"
database_name = "my-db"
database_id = "xxxxx-xxxx-xxxx"
Batch Operations
const results = await env.DB.batch([
env.DB.prepare("INSERT INTO users (name, email) VALUES (?, ?)").bind("Alice", "alice@example.com"),
env.DB.prepare("INSERT INTO users (name, email) VALUES (?, ?)").bind("Bob", "bob@example.com"),
env.DB.prepare("SELECT count(*) as total FROM users"),
]);
All queries execute in a single transaction — atomic and fast.
Migrations
# Create migration
wrangler d1 migrations create my-db add_posts_table
# Edit migration file
# migrations/0001_add_posts_table.sql:
# CREATE TABLE posts (
# id INTEGER PRIMARY KEY,
# title TEXT NOT NULL,
# content TEXT,
# author_id INTEGER REFERENCES users(id),
# created_at DATETIME DEFAULT CURRENT_TIMESTAMP
# );
# Apply
wrangler d1 migrations apply my-db
# Apply to production
wrangler d1 migrations apply my-db --remote
Time Travel (Point-in-Time Recovery)
# Restore to a specific point
wrangler d1 time-travel restore my-db --timestamp 2026-03-28T10:00:00Z
# List bookmarks
wrangler d1 time-travel info my-db
Free 30-day point-in-time recovery. Undo any mistake.
D1 + Hono (Modern API Framework)
import { Hono } from "hono";
type Bindings = { DB: D1Database };
const app = new Hono<{ Bindings: Bindings }>();
app.get("/api/posts", async (c) => {
const { results } = await c.env.DB.prepare(
"SELECT p.*, u.name as author FROM posts p JOIN users u ON p.author_id = u.id ORDER BY p.created_at DESC"
).all();
return c.json(results);
});
app.post("/api/posts", async (c) => {
const { title, content, author_id } = await c.req.json();
const post = await c.env.DB.prepare(
"INSERT INTO posts (title, content, author_id) VALUES (?, ?, ?) RETURNING *"
).bind(title, content, author_id).first();
return c.json(post, 201);
});
export default app;
Free Tier
| Resource | Free | Paid |
|---|---|---|
| Storage | 5 GB | 5 GB + $0.75/GB |
| Reads | 5M/day | Unlimited ($0.001/M) |
| Writes | 100K/day | Unlimited ($1.00/M) |
| Databases | 50 | 50,000 |
| Time Travel | 30 days | 30 days |
Need edge-first database architecture or Cloudflare Workers setup?
📧 spinov001@gmail.com
🔧 My tools on Apify Store
SQLite at the edge — is D1 the future of serverless databases?
Top comments (0)