← All posts

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.