← ブログ一覧

Cloudflare Workers + D1 で業務アプリを組むときの5つの勘所──バインディング、CPU時間、SQLite、マイグレーション、secret

CloudflareD1Workersバイブコーディング業務アプリ実装内製化中小企業

前の記事で、中小企業の業務アプリなら Cloudflare Workers + D1 を第一候補にしていいという話を書きました。サーバー管理が発生しない、起動待ちがない、必要なものが 1 か所に揃う——理由はそちらにまとめてあります。

この記事は、その実装編です。

Workers は、他のサーバー環境と勝手が違う部分があります。そこを知らずに始めると、「AI の言うとおりに書いたのに動かない」「なぜか無料枠を使い切る」で止まります。逆に、ここさえ押さえればあとは普通にコードを書くだけです。

詰まりやすい順に 5 つ、挙げます。


AI に Cloudflare で作らせる、具体的な指示

ここからは、実際に手を動かす人向けの話です。

まず指示の出し方。「バックエンドを作って」だけだと、たいてい Express + Heroku あたりが出てきます。こう書き足してください。

Cloudflare Workers で作って。データベースは D1、ファイル保管は R2 を使う。 フレームワークは Hono。設定は wrangler.jsonc に書いて。 接続情報は環境変数ではなくバインディング(env.DB のような形)で受け取る構成にして。 無料枠の CPU 時間 10ms を超えないように、重い同期処理は避けて。

最後の 2 行が重要です。理由は次で説明します。

勘所 1:接続文字列ではなく「バインディング」

ここが、他の環境から来た人がいちばん詰まる場所です。

普通のサーバー環境では、データベースに繋ぐとき接続文字列を使います。postgres://user:pass@host:5432/db のようなものを、環境変数に入れておく。

Workers は違います。設定ファイルで「この Worker には、この D1 を繋ぐ」と宣言しておき、コードからは env.DB のように受け取ります。

// wrangler.jsonc
{
  "name": "bihin-daicho",
  "main": "src/index.ts",
  "compatibility_date": "2026-08-01",
  "d1_databases": [
    { "binding": "DB", "database_name": "bihin", "database_id": "..." }
  ],
  "r2_buckets": [
    { "binding": "PHOTOS", "bucket_name": "bihin-photos" }
  ]
}
// コードからはこう触る
const { results } = await env.DB
  .prepare("SELECT * FROM items WHERE room_id = ?")
  .bind(roomId)
  .all();

await env.PHOTOS.put(`rooms/${roomId}/${photoId}.jpg`, file);

パスワードもホスト名も、コードにも環境変数にも出てきません。 バイブコーディングの記事で「秘密情報をそもそも置かない」と書きましたが、この構成だと置きようがない。設計として安全側に倒れています。

AI が接続文字列を使うコードを書いてきたら、それは他の環境向けの書き方が混ざっています。「バインディングで」と言い直してください。

勘所 2:CPU 時間は、待ち時間を含まない

無料枠の「CPU 時間 10ms」を見て、「10 ミリ秒で終わる処理なんて無理では」と思うかもしれません。誤解です。

CPU 時間は、実際にプログラムが計算していた時間だけを数えます。 外部 API の応答を待っている時間や、データベースの返事を待っている時間は含まれません

待つのはタダ。手を動かすと課金される。

だから、Claude API に画像を投げて 3 秒待っても、CPU 時間としては数ミリ秒です。備品台帳アプリが無料枠で動いているのは、これが理由です。

逆に、同期的な計算は容赦なく削られます。特に注意すべきなのが JSON の変換です。ある事例では、1.6KB のデータを await req.json() して JSON.stringify で返すだけで 5.6ms 消費したと報告されています。

10ms を超えると Error 1102 Worker exceeded resource limits でリクエストが打ち切られます。エラーが出たら、まず疑うのは重いループではなく JSONです。

対策はこの 3 つ。

  • 大きなデータを JSON で往復させない——受け取った本文をそのまま次に流す
  • 一覧を返すときは件数を絞る——全件返して手前で絞る、をやらない
  • 画像はバイナリのまま扱う——Base64 に変換すると、変換そのものが CPU を食う

勘所 3:D1 は SQLite。つまり、できないことがある

D1 の中身は SQLite です。だから普通の SQL は大体書けますが、PostgreSQL や MySQL の機能をそのまま持ち込むと落ちます

気をつけること内容
データ型型が緩い。日付は文字列か数値で持つのが素直
同時書き込み大量の同時書き込みには向かない。読み取り中心の用途が得意
全文検索拡張機能の有無を確認してから設計する
ストアドプロシージャ使えない。ロジックは Worker 側に書く
課金の単位読み書きした「行数」SELECT * で 1,000 件返せば 1,000 行分

最後の行が実務的に効きます。SELECT * を雑に書くと、無料枠を無駄に消費します。 必要な列だけ、必要な件数だけ取る——普通のことですが、ここでは金額に直結します。

勘所 4:テーブルは「マイグレーション」で作る

AI に「テーブルを作って」と言うと、SQL を出してくれます。それを手で実行して終わりにすると、後で必ず困ります。本番と手元で構造がずれるからです。

D1 には、変更を順番に記録して適用する仕組みがあります。

# 変更を1つのファイルとして作る
npx wrangler d1 migrations create bihin add_items_table

# 手元に適用(開発中)
npx wrangler d1 migrations apply bihin --local

# 本番に適用
npx wrangler d1 migrations apply bihin --remote

--local--remote は別のデータベースです。ここを混同して「データが入らない」と悩むのは、通過儀礼のようなものです。

Git の記事で「変更の履歴を残す」と書きましたが、データベースの構造にも同じことが要ります。マイグレーションのファイルは、Git で管理してください。

勘所 5:秘密情報は、ファイルに書かない

API キーなどは、コードにも設定ファイルにも書きません。

npx wrangler secret put ANTHROPIC_API_KEY
# 対話式で入力する。ファイルには残らない

コードからは、バインディングと同じように env.ANTHROPIC_API_KEY で取れます。.env をうっかりコミットする事故が、構造的に起きません。

AI が .env を使うコードを書いてきたら、wrangler secret に直させてください。


無料枠の壁と、その越え方

「無料で動く」と書きましたが、壁はあります。実務で当たる順に並べます。

無料枠当たったらどうするか
CPU 時間1 リクエスト 10msまず JSON の往復を減らす。それでも足りなければ有料へ
サブリクエスト数1 リクエストあたり 50 回外部 API を何十回も呼ぶ設計を見直す
1 日のリクエスト数10 万回社内ツールならまず超えない。超えるなら有料(月 $5)で十分
アップロードするコードのサイズ1MB 程度巨大なライブラリを入れない。軽いものを選ぶ

有料プランは月 $5 からで、リクエスト上限が月 1,000 万回になり、CPU 時間の制限も大幅に緩みます。

そして正直に書くと——業務で顧客のデータを扱うなら、最初から有料にしておくのが無難です。月 $5 は、無料枠を気にして設計を歪める時間より、はるかに安い。無料枠は「試す段階」と「社内の小さいツール」のためのもの、と考えるのが実務的です。

上限アラートは、最初に設定する

これは無料でも有料でも同じです。ダッシュボードから使用量の通知を設定できます。最初にやってください。 後回しにすると、次に見るのは請求書です。


業務アプリを自分で作るなら、最初に決めること

バイブコーディングで社内ツールを作るなら、コードを書き始める前に、これだけは決めてください

1. 置き場所を、自分で選ぶ

AI に「どこに置くのがいい?」と聞くのは構いません。ただしそのまま採用しない。「2026 年時点の無料枠と料金を調べて、比較して」と追加で指示する。検索機能があれば、その場で確認できます。

2. 課金の単位を確認する

回数で課金されるのか、時間で課金されるのか、データ量なのか。「止め忘れたらどうなるか」まで確認する。 ここを見ないと、私と同じことになります。

3. 上限アラートを設定する

多くのサービスに、使用量が一定を超えたら通知する機能があります。最初に設定する。 後回しにすると、次に見るのは請求書です。

4. 顧客データを置くなら、規約を確認する

無料だから何を置いてもいい、ではありません。顧客情報や個人情報を扱うなら、保管場所と規約を必ず確認してください。バイブコーディングの記事で書いた通り、いちばん怖いのは秘密情報の露出です。

5.「これは捨てられるか」を先に決める

同じく前回の記事の話です。試作なら気軽に。業務で毎日使うなら、保守する人を最初に決める。



この構成を選ぶ理由については

なぜ Cloudflare なのか、他と比べてどうなのか、料金はどうなっているのか——構成を選ぶ側の話は、前の記事にまとめてあります。

業務アプリを作るなら、まず Cloudflare と D1 を検討してほしい AI の言うとおり Heroku で作って請求が来た話、「なんで無料なの、詐欺?」への答え、標準にした 5 つの理由、他の選択肢との比較、510 室の備品台帳を構築した実例。


まとめ

  • 接続文字列ではなくバインディング——設定ファイルで宣言し、env.DB で受け取る。パスワードもホスト名もコードに出てこないので、秘密情報を置きようがない
  • CPU 時間は待ち時間を含まない——外部 API を 3 秒待ってもほぼ加算されない。重いのは JSON の変換Error 1102 が出たら、まず疑うのは重いループではなく JSON
  • D1 は SQLite——型は緩く、同時書き込みは苦手、ストアドは使えない。そして課金は読み書きした行数SELECT * を雑に書くと金額に響く
  • テーブルはマイグレーションで管理——--local--remote は別のデータベース。ファイルは Git に入れる
  • 秘密情報は wrangler secret put——.env をうっかりコミットする事故が構造的に起きない
  • 無料枠の壁は CPU 10ms・サブリクエスト 50・1 日 10 万リクエスト・コードサイズ 1MB。ただし業務で顧客データを扱うなら、最初から月 $5 の有料にしておくのが無難

AI に投げるときは、この一行を足してください。

「Cloudflare Workers で作って。DB は D1、ファイルは R2。フレームワークは Hono。接続情報は環境変数ではなくバインディングで。CPU 時間 10ms を超えないよう、重い同期処理は避けて」

これだけで、Express + Heroku のコードが出てこなくなります。

Acetyl:Tech は、社内で作ったものを「業務で任せられる状態」にするところから支援しています。 動いてはいるけれど不安がある、というご相談も承ります。詳しくは「業務アプリ開発」のページをご覧ください。


出典・参考

料金・仕様は変動します。実装前に必ず公式ドキュメントでご確認ください。

Read next

他の記事

AI・DXの導入、どこから手をつけるか迷ったら

Acetyl:Techが、あなたの会社で「本当に使われる形」まで設計します。まずはお気軽にご相談ください。

無料で相談する