April 2, 2026
Getting Started with Cloudflare D1 and Next.js
Learn how to build a full-stack application using Next.js on Cloudflare Pages with D1 as your database — no traditional server required.
Introduction
Cloudflare D1 is a serverless SQLite database that runs at the edge, right alongside your Cloudflare Workers and Pages projects. Combined with Next.js, it enables you to build full-stack applications that are globally distributed, fast, and cost-effective.
In this guide, we'll walk through everything you need to get started — from setting up your project to querying your database in server components and API routes.
Why D1?
Traditional databases require you to run a server, manage connections, and handle scaling. D1 takes a different approach:
- Serverless — no connection pooling, no idle costs
- Edge-native — runs close to your users
- SQLite-compatible — familiar SQL syntax, great tooling
- Free tier — generous limits for most projects
Setting Up the Project
First, create a new Next.js project:
npx create-next-app@latest my-blog --typescript --tailwind --app
cd my-blog
Then install the Cloudflare adapter:
npm install --save-dev @cloudflare/next-on-pages wrangler
Configuring wrangler.toml
Create a wrangler.toml file at the root of your project:
name = "my-blog"
compatibility_date = "2025-01-01"
compatibility_flags = ["nodejs_compat"]
pages_build_output_dir = ".vercel/output/static"
[[d1_databases]]
binding = "DB"
database_name = "my-blog-db"
database_id = "YOUR_DATABASE_ID"
Replace YOUR_DATABASE_ID with the ID from running:
npx wrangler d1 create my-blog-db
Writing Your First Migration
Create a migrations/ folder and add your schema:
-- migrations/0001_create_posts.sql
CREATE TABLE IF NOT EXISTS posts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
slug TEXT NOT NULL UNIQUE,
title TEXT NOT NULL,
content TEXT NOT NULL,
published INTEGER NOT NULL DEFAULT 0,
created_at TEXT NOT NULL DEFAULT (datetime('now'))
);
Apply it locally:
npx wrangler d1 execute my-blog-db --local --file=./migrations/0001_create_posts.sql
Querying D1 in Server Components
With @cloudflare/next-on-pages, you can access your D1 binding via getRequestContext:
import { getRequestContext } from "@cloudflare/next-on-pages";
export const runtime = "edge";
export default async function HomePage() {
const { env } = getRequestContext();
const { results } = await env.DB.prepare(
"SELECT * FROM posts WHERE published = 1"
).all();
return (
<ul>
{results.map((post) => (
<li key={post.id}>{post.title}</li>
))}
</ul>
);
}
Note the export const runtime = "edge" — this is required for any route that accesses Cloudflare bindings.
Deploying
Build and deploy with:
npx @cloudflare/next-on-pages
wrangler pages deploy .vercel/output/static --project-name my-blog
Run the remote migration once:
npx wrangler d1 execute my-blog-db --remote --file=./migrations/0001_create_posts.sql
Conclusion
Cloudflare D1 with Next.js is a compelling stack for building fast, globally-distributed applications. The edge-native model eliminates cold starts, reduces latency, and keeps infrastructure costs low.
As D1 matures, expect better support for read replicas, larger storage limits, and deeper integrations with the rest of the Cloudflare ecosystem.