以下の記事で D1 を試しましたが、KV (Workers KV) も触ってみましょう。

ちなみに、KVとD1 の料金を比較すると、D1の方が圧倒的に安いです。 感覚的にはD1の方が高いのではないか、と考えていたので意外でした。D1を積極的に使いましょう。

KV の料金

※2026/1時点

ItemFree planPaid plan
Keys read100,000 / day10 million / month, + $0.50 / million
Keys written1,000 / day1 million / month, + $5.00 / million
Keys deleted1,000 / day1 million / month, + $5.00 / million
List requests1,000 / day1 million / month, + $5.00 / million
Stored data1 GB1 GB, + $0.50 / GB-month

D1 の料金

※2026/1時点

ItemWorkers FreeWorkers Paid
Rows read5 million / dayFirst 25 billion / month included + $0.001 / million rows
Rows written100,000 / dayFirst 50 million / month included + $1.00 / million rows
Storage (per GB stored)5 GB (total)First 5 GB included + $0.75 / GB-mo

特徴

📌 Workers KV

  • グローバルな key–value ストレージ。
  • 読み込みはキャッシュ効いた高速アクセスが得意。
  • リクエスト数とストレージ容量で課金。
  • 追加リクエストは読取 $0.50 / 1M 、書込・削除・一覧 $5 / 1M と高め。
  • 1GB のストレージまで無償(Free/KV付属)あり。

📌 D1

  • SQL データベース(SQLite ベース)の 構造化データ格納・クエリ 向け。
  • 行ベースの課金:読み込み $0.001 / 1M 行、書き込み $1.00 / 1M 行、ストレージ $0.75 / GB-月(Paid)。
  • KV と比べて 行読み込みの価格が桁違いに安い(KV は 0.5$ / 1M 読み込みに対し D1 は 0.001$ / 1M)。

KV のユースケース

「書き込みは少なく、読み込みが(圧倒的に)多い」ユースケースが向いているようで、 ユースケースとしては以下のあたりがよいのではないか、と思われます。

  • ゲームのハイスコア
  • セッション情報
  • 設定情報
  • キャッシュ
  • マスタデータ配信

色々書きましたが、実際に触ってみましょう。 今回紹介するサンプルコード全量は以下にあります。

テンプレートの準備

以下のコマンドを実行し、テンプレートを作成します。

wrangler init my-app

カテゴリに Framework Starter を選択し、フレームワークとして Next.js を選択します。

ローカルKVの作成とデータ登録

D1 同様、ローカル環境に KV インスタンスを設定できます。

"kv_namespaces": [
	{
		"binding": "KV_TEST",
		"id": "my-app-kv"
	}
]

キーの一覧を確認しましょう。

npx wrangler kv key list --binding=KV_TEST --local
[]

となり、明示的に create しなくても取得できました。

次に、キーを登録してみます。

npx wrangler kv key put aaa bbb --binding=KV_TEST --local

登録したキーを確認します。

npx wrangler kv key list --binding=KV_TEST --local
[
  {
    "name": "aaa"
  }
]

以下のコマンドでも登録したキー・バリューを確認できるはずですが、 自分が実行した環境では不具合?があるようで一瞬表示されるのですが次のプロンプトによって出力された値が上書きされてしまい、 実質表示されない状態になっていました。

npx wrangler kv key get aaa --binding=KV_TEST --local

テストアプリでのKVアクセス

API経由でデータを取得してみます。

import { getCloudflareContext } from "@opennextjs/cloudflare";

export async function GET(
  req: Request,
) {
  const { env } = getCloudflareContext();
	const kv = env.KV_TEST;

  const { searchParams } = new URL(req.url);
  const key = searchParams.get("key");
  if (!key) return new Response("key required", { status: 400 });

  const value = await kv.get(key);
  return Response.json({ key, value });
}
declare namespace Cloudflare {
	interface Env {
		NEXTJS_ENV: string;
		WORKER_SELF_REFERENCE: Fetcher /* cf-kv-test */;
		IMAGES: ImagesBinding;
		ASSETS: Fetcher;
		KV_TEST: KVNamespace; /* 追加 */
	}
}

起動

npm run dev
curl "localhost:3000/api/kv/get?key=aaa"

以下のようなレスポンスが返ってくればOKです。

{"key":"aaa","value":"bbb"}%

Cloudflare Workers 上で動作確認

Cloudflare 上に KV を作成します。

npx wrangler kv namespace create my-app-kv
"kv_namespaces": [
	{
		"binding": "KV_TEST",
		"id": "my-app-kv"
	},
	{
		"binding": "my_app_kv",
		"id": "e4b2daceea6e4aa88d0be37547439ffd"
	}
]

my-app-kv を作成した直後は↑のようになると思うので、以下のようにマージします。 ちなみに、このように設定しておいても、D1同様 remote: true 句がなければ(ローカルで実行した場合)デフォルトでローカルKVを参照します。

"kv_namespaces": [
	{
		"binding": "KV_TEST",
		"id": "e4b2daceea6e4aa88d0be37547439ffd"
	}
]

サンプルアプリを Cloudflare 環境にデプロイします。

npm run deploy

リモートKV にデータを登録します。

npx wrangler kv key put ccc ddd --binding=KV_TEST --remote

データを確認します。

npx wrangler kv key list --binding=KV_TEST --remote
npx wrangler kv key put ccc ddd --binding=KV_TEST --remote

データが入っていることが確認できたら、ローカル同様に curl で API を叩きます。 こちらで同じように値が返却されれば完成です。

curl "https://my-app.xxx.workers.dev/api/kv/get?key=ccc"
{"key":"ccc","value":"ddd"}%

以上です、お疲れ様でした。後片付けも忘れずに。

後片付け

アプリの削除

npx wrangler delete my-app-kv

KVの削除

npx wrangler kv namespace delete --binding=KV_TEST