【Cloudflare D1入門】概要からVPS比較、ローカル開発・本番デプロイまで完全ガイド

cloudflare-d1 インフラ・サーバー

Cloudflareが提供するサーバーレスSQLデータベース「Cloudflare D1」。

本記事では、D1の概要や従来のVPS(PostgreSQLコンテナ)運用との違いを解説した上で、実際に手を動かしてローカル開発から本番環境へデプロイする手順までを解説します。

1. Cloudflare D1 とは?(概要)

Cloudflare D1 は、Cloudflareのエッジネットワーク上で動作するエッジネイティブなサーバーレスSQLデータベースです。軽量で信頼性の高い SQLite をベースに構築されています。

主な特徴

  • ゼロレイテンシ接続: Cloudflare Workers / Pages と同じ基盤上で動くため、DB接続時のネットワーク遅延がほぼありません。
  • リードレプリケーション: 書き込みは単一のプライマリで行われますが、読み取りは世界中のエッジに自動分散されるため参照処理が高速です。
  • Time Travel(タイムトラベル): 過去30日間の任意の時点にDBの状態を復元できるバックアップ機能が標準搭載されています。
  • 手厚い無料枠: 無料プランでも1日あたり500万行の読み取り、10万行の書き込みが可能で、データ転送量(Egress)の追加課金もありません。

2. D1 vs VPS(Docker + PostgreSQL)比較

Webサービスを個人開発・運用する際によく比較される「VPS上のDockerコンテナでPostgreSQLを動かす構成」とD1の違いをまとめました。

比較項目Cloudflare D1VPS + Docker + PostgreSQL
ベース技術SQLitePostgreSQL
インフラ管理不要(完全マネージド)必要(OS・Docker・DB保守)
バックアップ自動(30日間のTime Travel)自前で設定(pg_dumpなど)
読み取り性能エッジ分散で超高速VPSの物理的な場所に依存
機能性・拡張性SQLiteの標準機能高度(JSONB, pgvector, PostGIS等)
接続レイテンシWorkersからほぼ0msインターネット越しの接続遅延あり
コスト無料枠大+従量課金VPSの月額固定費

どちらを選ぶべき?

  • D1がおすすめ: インフラ管理の手間(パッチ適用やバックアップ)をゼロにしたい場合、読み取りメインのWebアプリ、コストを最小限に抑えたい場合。
  • VPS+PostgreSQLがおすすめ: 複雑な検索機能(JSONBやベクトル検索)が必要な場合、書き込みの頻度・コンカレンシーが非常に高い場合。

3. プロジェクトの作成コマンド

まずは Cloudflare Workers のプロジェクトを新規作成します。

# Workersプロジェクトの作成
npm create cloudflare@latest my-d1-app

いくつか対話形式で答えていきます。

  • What would you like to start with? → 今回はHonoを使うので category Framework Starter
  • Which development framework do you want to use? →  Honoを選択
  • Do you want to use git for version control? → git管理したい人はYes
  • Do you want to deploy your application? → まずはローカルで開発してからデプロイするのでNo

これで my-d1-app というプロジェクトが生成されます。

# 作成したディレクトリへ移動
cd my-d1-app

4. 生成されたファイル、ディレクトリの解説

1. src/

アプリケーションのプログラム(TypeScriptコード)を入れる最重要ファイルです。

  • 中にある index.ts(エントリーポイント)に Hono のルーティング処理(app.get(‘/’, …))や D1 の操作ロジックを書いていきます。

2. public/

画像やCSS、HTMLなどの静的ファイル(Static Assets)を入れる場所です。

  • デフォルトで index.html が入っています。Webブラウザでアクセスした際にそのまま返したいアイコン画像(favicon.ico)やフロントエンドの静的ファイルを配置します。

3. node_modules/

npm install でインストールされたライブラリ(HonoやWranglerなど)の実体が入る場所です。

  • 容量が大きく自動生成されるため、直接触ることはありません(Git管理も除外されます)。

4. wrangler.jsonc(設定ファイル)

Cloudflare Workers や D1 の設定を記述する超重要ファイルです。

  • 従来の wrangler.toml に代わる JSON形式(コメントが書ける .jsonc)の設定ファイルです。

5. package.json & package-lock.json

プロジェクトで使うライブラリの管理ファイルです。

  • package.json: インストールしたパッケージ名(hono や wrangler)や、実行コマンド(npm run dev など)が記録されています。
  • package-lock.json: 依存ライブラリの正確なバージョン情報が固定記録されているファイルです。

6. worker-configuration.d.ts & tsconfig.json

TypeScriptの型定義・設定ファイルです。

  • worker-configuration.d.ts: Wrangler が自動生成してくれる型定義ファイルです。wrangler.jsonc に D1 の設定を書いた後、npm run cf-typegen を実行すると env.DB の型が自動補完されるようになります。
  • tsconfig.json: TypeScriptのコンパイルルールが書かれた設定ファイルです。

7. .gitignore & README.md

  • .gitignore: Gitで管理したくないファイル(node_modules やローカルテスト用のDBなど)を指定するリストです。
  • README.md: プロジェクトの概要や動かし方を書くメモファイルです。

今後の開発で主に触るファイルはこの2つだけ!

今回は基本的には、以下の2つを行き来して開発を進めていくことになります。

  1. wrangler.jsonc: D1 データベースなどのインフラ設定を書き込む
  2. src/index.ts: Hono を使って D1 からデータを取得・追加するAPIコードを書く

5. D1データベースの構築コマンド

Wrangler CLI を使って、Cloudflare上に D1 データベースを作成します。

# 「my-db」という名前でD1データベースを作成
npx wrangler d1 create my-db

コマンドを実行すると、ターミナルに以下のような出力が表示されます。

✅ Successfully created DB 'my-db' in region APAC

[[d1_databases]]
binding = "DB"
database_name = "my-db"
database_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"

他にも対話形式で答えていきます。

  • Would you like Wrangler to add it on your behalf? … Wrangler が wrangler.jsonc を自動的に読み込んで設定ファイルを編集してくれるので yes
  • What binding name would you like to use? … デフォルトのmy_dbのままにします。 プログラム(Hono)側で呼び出すとき、c.env.my_db という名前になります。
  • For local dev, do you want to connect to the remote resource instead of a local resource? … ローカル開発(テスト)中に、PC内のテスト用DBではなく、Cloudflare上にある本番のD1データベースに直接繋ぎますか?という質問なので no。
    PC内のローカルSQLiteを使って開発します。本番データを誤って削除したり汚したりする心配がなく、安全にテストできます。

仕上げに、VS Codeなどのエディタで c.env.my_db の補完が効くように型定義ファイルを更新しておきましょう。

npm run cf-typegen

6. スキーマ作成とテーブル定義の適用

テーブルを作成するためのSQLファイルを用意し、ローカル環境のD1に反映させます。

① SQLファイルの作成(schema.sql)

プロジェクトルートに schema.sql を作成します。

DROP TABLE IF EXISTS users;

CREATE TABLE IF NOT EXISTS users (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  name TEXT NOT NULL,
  email TEXT UNIQUE NOT NULL,
  created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);

-- 動作確認用のサンプルデータ
INSERT INTO users (name, email) VALUES ('山田太郎', 'taro@example.com');
INSERT INTO users (name, email) VALUES ('鈴木花子', 'hanako@example.com');

② ローカルDBにスキーマを適用

–local フラグを付けて実行します。

npx wrangler d1 execute my-db --local --file=./schema.sql

🚣 4 commands executed successfully. のようなメッセージが出れば、schema.sql に書いた 4つのSQL(DROP, CREATE, INSERT ×2) がローカルのSQLiteにすべて正常に適用されたことを示しています。

これでローカルのDB環境は完璧に整いました。

7. アクセスするAPI Hono のコードを書いてみよう!

それでは、Hono からこの users テーブルのデータを取得・追加するコードを書いてみましょう。

src/index.ts を開いて、コードを以下のように書き換えます。

import { Hono } from 'hono'

// CloudflareBindings の型を指定して Hono を初期化
const app = new Hono<{ Bindings: CloudflareBindings }>()

// 1. ユーザー一覧を取得する API
app.get('/users', async (c) => {
  // wrangler.jsonc で設定した "my_db" を使用
  const { results } = await c.env.my_db.prepare('SELECT * FROM users').all()
  return c.json(results)
})

// 2. ユーザーを新規登録する API
app.post('/users', async (c) => {
  const body = await c.req.json<{ name: string; email: string }>()
  
  const result = await c.env.my_db
    .prepare('INSERT INTO users (name, email) VALUES (?, ?)')
    .bind(body.name, body.email)
    .run()

  return c.json({ message: 'User created successfully', result })
})

export default app

8. 動作確認(ローカル開発サーバー起動)

コードを保存したら、ローカルサーバーを起動してみましょう。

npx wrangler dev

起動後、ブラウザや curl コマンドで確認します。

  1. D1データ取得確認: ブラウザで http://localhost:8787/users にアクセス ➔ 先ほど schema.sql で入れた山田太郎・鈴木花子のデータが JSON で表示されます。
  2. D1データ新規登録確認:開発サーバーを立ち上げたまま、別のターミナル(PowerShell)から以下の curl コマンドを叩くことでテストできます。
curl -X POST http://localhost:8787/users `
  -H "Content-Type: application/json" `
  -d '{"name": "佐藤二朗", "email": "jiro@example.com"}'

実行後に再度ブラウザで http://localhost:8787/users にアクセスし、佐藤二朗さんのデータが追加されていれば登録処理も機能しています!

9. 本番デプロイ

動作確認ができたら、本番のD1データベースへスキーマを反映し、Workersのコードをデプロイします。

① 本番(Cloudflare)の D1 にテーブルを作成

–remote フラグを付けて実行。

npx wrangler d1 execute my-db --remote --file=./schema.sql

② 本番環境へデプロイ

npx wrangler deploy

10. Workersからデータベースを確認するコマンド

デプロイ後、本番環境のD1に対して直接クエリを実行してデータを確認することができます。

本番(リモート)DBのデータをコマンドで確認

npx wrangler d1 execute my-db --remote --command="SELECT * FROM users"
  • –remote : ローカル(PC内)ではなく、Cloudflare 上の本番 DB に対して実行することを明示します。
  • –command=”…” : 実行したい SQL 文を直接指定します。

他にも発行された本番URL https://my-d1-app.あなたのID.workers.dev/users にブラウザでアクセスしてもデータが確認できます。

認証セッションの期限切れが起きたら

作業中に code: 7403 のエラー(The given account is not valid or is not authorized to access this service)が出ることがあります。

これは、CLI(Wrangler)が認識している アカウントID が実際の所有アカウントと一致していないか、認証セッションの期限切れ・権限不整合が起きていることが原因です。

以下の手順で再ログインとアカウント設定を行うことで解決できます。

🛠️ 解決手順

1. Wrangler で再ログイン(認証情報の更新)

一度再認証を行ってトークンを新しくします。

npx wrangler login
  1. ブラウザが自動で立ち上がります。
  2. ログイン画面が開いたら 「Allow(許可)」 を押します。

まとめ

Cloudflare D1を使うことで、インフラ管理や接続のオーバーヘッドに悩まされることなく、超低遅延なサーバーレスデータベースを構築できます。

Workers/Pages/Hono との親和性も非常に高いため、個人開発や軽量なWebアプリケーションを作成する際はぜひ試してみてください。

コメント