← Documents
Ops · Workers + D1 · Step-by-Step

Workers + D1 のWebアプリを立ち上げる
——テンプレートから10手順、毎回これを見ればいい

2026年8月8日に実際にデプロイまで通した手順です。読み物ではなく作業手順書として書いてあります——上から順に実行してください。
踏んだ落とし穴は、それが起きるステップの中に埋め込んであります。後ろにまとめて置くと、詰まってから探すことになるからです。順序には依存関係があり、入れ替えると必ずどこかで失敗します。

起点:テンプレートから複製 順序:D1 → Worker ローカル環境:不要

1この手順書の使い方

表記意味
[ブラウザ]Safari 等で画面を操作する。iPad で可
[エージェント]Claude Code に頼む。指示文をそのまま載せてある
[人]値を決める。エージェントに推測させない
そのステップで実際に踏んだ落とし穴。読み飛ばさない
ローカルに Node は要りません。すべてブラウザとクラウド実行環境で完結します。手元でビルドを走らせる場面はありません。
アプリの中身が決まっていないなら、雛形のまま最後まで通してください。接続の問題とアプリの問題を同時に切り分けるのは大変です。動くと分かっている雛形で経路を確定させてから中身を作るほうが、結果的に早く終わります。

2前提と検証済みの組み合わせ

必要なもの:GitHub アカウント/Cloudflare アカウント/テンプレート化済みのリポジトリ(→Step 1

項目バージョン確認したこと
Node2220 だとデプロイ段だけが落ちる。下の注記を読むこと
wrangler4.120.0engines.node>=22.0.0deploy --dry-run認証情報なしで完走する
@cloudflare/workers-types5.x^4 だと wrangler 4系の peer 依存と衝突して npm ci が落ちる。「wrangler 4 なら types も 4」は誤り
typescript5.xtsc --noEmit が通る
⚠ Node のバージョンは、雛形側で修正済みです。複製すれば踏みません。ただし症状を知っておく価値があります。

.nvmrc20 だと、Cloudflare のビルド環境が Node 20 を入れます。すると npm ci警告で通ってしまうため、「ビルド中」まで緑で「デプロイ中」だけが数秒で赤くなります。
npm warn EBADENGINE package: 'wrangler@4.120.0',
npm warn EBADENGINE required: { node: '>=22.0.0' },
npm warn EBADENGINE current: { node: 'v20.20.2' }
教訓:.nvmrc と検証環境の Node が食い違っていると、その検証はビルド環境を代表しません。実際この雛形は公開前に npm installtsc--dry-run を通していましたが、検証環境が Node 22 だったため .nvmrc20 が一度も使われていませんでした。

3全体像(10ステップ)

#やること場所この順である理由
1テンプレートから複製ブラウザ空のリポジトリを作らない
2前のアプリの値を消すエージェント
3作るものを決める4以降で使う値が要る
4D1 を作るブラウザWorker より先。Worker は最初のデプロイ成功時に生まれる
5wrangler.jsonc に実値エージェント4 の Database ID が要る
6schema.sql を実行ブラウザ初回デプロイより前。無いと画面だけ500になる
7Workers Builds に接続ブラウザ
8main にマージエージェントここで初めて自動デプロイが走る
9動作を確認ブラウザ読み書きの両方
10main を保護ブラウザ

4Step 1–3:複製して初期化する

Step 1 [ブラウザ]テンプレートから新しいリポジトリを作る

  1. 元リポジトリの Code タブ(Settings ではない)を開く
  2. 緑の Use this templateCreate a new repository
  3. Repository name を入力
  4. Include all branches は Off のままmain だけでよい。作業ブランチは不要)
  5. Visibility は Private でよい
  6. Create repository
⚠ 空のリポジトリを作らないこと。テンプレートから複製すると、CLAUDE.md・雛形・CIワークフローが最初から入った状態で始まります。空のリポジトリだとエージェントは何の指示も持たない状態から始まり、毎回口頭で説明することになります。
テンプレート化がまだなら、元リポジトリの Settings → General → Template repository にチェックを入れるだけです。以後 Use this template が出ます。複製先は履歴を引き継がず、コミット1本から始まります。
Private のままで問題ありません。公開されるのは Cloudflare が配信するものだけで、リポジトリの可視性とは別です。

Step 2 [エージェント]前のアプリの値を消す

  1. claude.ai/code を開く
  2. サイドバーから新しいセッションを開始し、リポジトリに複製先を選ぶ
  3. 最初のメッセージで 「テンプレートをリセットして」
機械が戻すもの人が決めてエージェントが書き換えるもの
wrangler.jsoncnamedatabase_namedatabase_idchange-me
package.jsonnamedescription
複製元の環境記録(docs/SETUP.md 等)は削除
README.md … このアプリの説明に
src/index.ts … 作るものに合わせて
schema.sql … テーブル定義を作るものに合わせて
⚠ セッションは必ず複製先のリポジトリに紐づけること。元リポジトリで開いたセッションからは、複製先のファイルに触れません。「新しいセッション」を作る必要があります——同じ会話の続きではできません。

Step 3 [人]作るものを決める

項目用途制約
アプリ名wrangler.jsoncname*.workers.dev のサブドメインにもなる小文字の英数字とハイフンのみ。大文字を含むと wrangler が弾く
何をするアプリかREADME.md/画面の見出し/src/index.ts の方針
D1 データベース名wrangler.jsoncdatabase_nameStep 4 で作る名前と一致させる
公開ドメインroutes。指定なしなら <アプリ名>.<サブドメイン>.workers.dev独自ドメインは Cloudflare のゾーン配下に置く必要あり

5Step 4–6:Cloudflare側を先に作る

Step 4 [ブラウザ]D1 データベースを作る

  1. Cloudflare ダッシュボード → ストレージとデータベース → D1 SQLite データベース
  2. 作成。名前は Step 3 で決めたもの
  3. データ ロケーションは「位置情報」(自動配置)のままでよい
  4. 作成後の画面に出る Database ID をコピー
⚠ Worker より先に D1 を作ること。wrangler deploy は実行時に database_id を Cloudflare に問い合わせて解決します。D1 が存在しないと最初のデプロイが成功せず、Worker 自体が作られません。

Worker は手で作るものではなく、最初のデプロイ成功時に生まれます。「先に Worker を作ろう」として詰まるのが典型です。

Step 5 [エージェント]wrangler.jsonc に実値を入れる

Step 3 と 4 で決まった値をエージェントに渡します。change-me は3か所です。

grep -rn 'change-me' wrangler.jsonc   # 何も出ないこと
npm install                           # package-lock.json の name を同期
npm run check                         # 通ること
npm install を忘れない。package.jsonname を変えると package-lock.json と食い違い、ビルド環境の npm ci が落ちます。

Step 6 [ブラウザ]schema.sql をコンソールで実行する

  1. D1 の画面 → コンソール タブ
  2. schema.sql の中身を貼って実行(複数文をまとめて受け付けます
  3. 「概要」タブのテーブル数が増えれば成功
⚠ 初回デプロイより前に必ず済ませること。テーブルが無くてもデプロイは成功します。そして画面を開いた瞬間に 500 になります。ビルドログは緑なので、原因が分かりにくい失敗です。

6Step 7–8:つないでデプロイする

Step 7 [ブラウザ]Workers Builds に接続する

コンピュート → Workers & Pages からリポジトリをインポートします。

項目
Build commandnpm ci
Deploy commandnpx wrangler deploy
ルート ディレクトリ/
Production branchmain
ビルド出力ディレクトリ空のまま。静的アセット用の項目で、Worker アプリでは使わない
GitHub App の認可では Only select repositories を選び、対象リポジトリだけに絞ること。この認可はAPI では代替できない唯一の関門ですが、アカウント/組織ごとに一度行えば以後は使い回されます。

Step 8 [エージェント]main にマージする

作業ブランチで開発 → npm run check が通ることを確認 → main へ。ここで初めて自動デプロイが走ります。

assets.directory エラー
[ERROR] The directory specified by the "assets.directory" field in your ...
   /opt/buildhome/repo/dist
症状:クローン・インストール・ビルドは緑なのに、デプロイだけ失敗する。
原因:assets.directory静的サイト版の設定main が古い構成のまま接続すると、Cloudflare はそちらを読みます。
見分け方:ログの audited 1 package(正しければ42前後)と、npx がその場で wrangler を取りに行っていること(正しければ npm ci で入っているので取りに行かない)。
対処:main に正しい構成をマージする。このステップを先に済ませれば起きません。
refusing to merge unrelated histories
クラウド実行環境で、ローカルの mainorigin/main と無関係な履歴になっていることがあります。テンプレートから作ったリポジトリは履歴を引き継がないので起きやすい。
git checkout -B main origin/main
git merge --ff-only <作業ブランチ>

7Step 9–10:確認して保護する

Step 9 [ブラウザ]動作を確認する

https://<アプリ名>.<サブドメイン>.workers.dev を開きます。

⚠ ビルド成功は「Worker が配置された」ことまでしか意味しません。D1 への読み書きが通るかは、画面を開いて初めて分かります。上の2つ目まで確認して完了です。

Step 10 [ブラウザ]main を保護する

GitHub の Settings → Branchesmain を保護し、build チェックの通過を必須にします。

これで「壊れたものを本番へ送る経路」が構造的に消えます。CI(型チェック+バンドル検証)を通らないものは main に入れません。設定はiPadのSafariから行えます。

8詰まったら:ビルドログ5段階

Workers Builds のログは5段階に分かれます。どこが赤いかで原因の範囲が決まるので、まず段階を特定してください。ログを上から丁寧に読むより速い。

赤い段階疑うもの
初期化接続設定そのもの
クローンブランチ指定、リポジトリの権限
インストールpackage-lock.json の不整合、依存の解決、workers-types のメジャー
ビルドBuild command そのもの
デプロイwrangler.jsonc の内容・Node のバージョン・D1 の実在
実際に踏んだ落とし穴は、4件のうち3件が「デプロイ段だけ赤い」でした。この段が赤いときに疑うものは3つしかないので、順に潰せば必ず当たります。
ビルドが失敗しても本番は壊れません。Cloudflare は最後に成功したデプロイを配信し続けます(エラー画面にはならない)。「push したのに変わらない」ときは、まずビルドログを見ること。

9手元の検証で分かることの限界

npm run checktsc --noEmitwrangler deploy --dry-run です。--dry-run は認証情報なしで動く代わりに、Cloudflare に問い合わせません。その線引きがそのまま限界になります。

分かる分からない
型エラーdatabase_id が実在するか
wrangler.jsonc の書式(Worker 名の規則違反など)D1 にテーブルがあるか
main が指すファイルの実在ビルド環境の Node で動くか
バインディングの「形」が解決すること実際にデプロイが通るか
右の列は本番デプロイでしか確かめられません。そして今回踏んだ落とし穴は、すべて右の列にありました。

npm run check間違いを早く見つけるための道具であって、正しさの証明ではありません。「手元が全部緑」はこの構成では出発点にすぎない。

10中身を作る前に設計すること

雛形の src/index.ts には POST /api/items があり、これは誰でも書き込めます。経路確認の段階では問題ありませんが、URL が知られた状態で放置するとスパムを入れられます。

Step 3 で「何をするアプリか」を決めるときに、一緒に決めてください。

「とりあえず公開して後で塞ぐ」はしない——静的サイトが「書き込み経路を作らない」ことで安全を買っていたのに対し、こちらは書き込み経路がある前提で設計する必要があります。守るべきものが入れ替わっています。

コード側で守る3点。
SQL に値を入れるときは必ず .bind()——文字列連結で SQL を組み立てない
HTML に値を差し込むときは必ずエスケープ——テンプレートリテラルへの直挿しは XSS
入力は使う前に検証する——await req.json() の戻り値は unknown として扱い、型・長さ・必須を確認してから使う

S情報ソース

2026年8月時点。本記事はこのライブラリの中では例外的に一次情報の比率が高いものです。推測や二次情報ではなく、実際に構築した際の記録に基づきます。

  • 【一次記録・実施者による】 10手順・落とし穴4件・ビルドログの段階別の切り分け・ダッシュボードの画面名(「ストレージとデータベース」「コンピュート」「コンソール」「概要」等)・「ビルド成功はWorkerが配置されたことまでしか意味しない」という指摘は、2026年8月8日に実際にデプロイまで通した際の記録に基づきます。エラーメッセージは実際に出力されたものです。
  • 【本環境で実測】 wrangler 4.120.0 の engines.node>=22.0.0 であることは node_modules/wrangler/package.json を読んで確認。@cloudflare/workers-types^4 が peer 依存と衝突して npm ci が落ちること、wrangler.jsoncname が小文字英数字とハイフンのみであること、deploy --dry-run が認証情報なしで完走することも実行して確認しています。
  • 【修正済み】 Node のバージョンの件は、このリポジトリが配っていた雛形(tools/webapp-template/)のバグでした。.nvmrc22engines.node>=22 に修正済みです。あわせて、同じ理由で npx wrangler deploy を使う本リポジトリ自身の .nvmrc も 22 に更新しています。
  • 【確認していないこと】 Cloudflare のビルド環境が .nvmrc をどう解釈するかの正確な仕様。本記事は.nvmrc が 20 だと Node 20 が入り、デプロイが落ちた」という観測に基づいており、公式ドキュメントでの裏取りはしていません。またダッシュボードの画面名は日本語表示での記録であり、表示言語や UI 更新で変わりえます。

H更新履歴

日付内容
2026-08-08読み物から作業手順書へ組み替えた。繰り返し使うものなので、上から順に実行できる形を優先した。最大の変更は落とし穴を後ろにまとめず、それが起きるステップの中へ移したこと——後ろに置くと、詰まってから探すことになるため。あわせて各ステップに[ブラウザ][エージェント][人]の区別と、ダッシュボードの実際の画面名・入力値・確認コマンドを明記した。Step 1 を「空のリポジトリを作る」から「テンプレートから複製する」へ訂正(テンプレート化する前に書いた手順が残っていた)。npm install を忘れると package-lock.jsonname が食い違って npm ci が落ちる点を Step 5 に追記した。
2026-08-08初版公開。Workers + D1 の Webアプリを実際に構築した記録をまとめた。最大の発見は、wrangler 4.120.0 が Node 22 以上を要求するのに雛形が .nvmrc: 20 を配っていたこと。インストールは EBADENGINE の「警告」で通るため、ビルドが成功しているように見えてデプロイだけが落ちる。雛形の公開前検証は通っていたが、その環境の Node が 22 だったため .nvmrc の値が一度も使われていなかった。本記事の公開と同時に雛形と本リポジトリ双方の .nvmrc を 22 に修正した。

関連ドキュメント