個人で SaaS を作り、Claude Code に支払うコストより多くを稼ぐ。このシンプルな目標に向けて、私は 2026 年 2 月から 90 日間の記録をつけ続けました。この記事はその全工程の公開ノートです。
成功談を並べたいわけではありません。つまずいた箇所、判断ミス、トークンを無駄にした失敗も含めています。それらこそが、次に同じことをしようとしている方に一番役立つと思うからです。
そしてもうひとつ。公開から数ヶ月が経ち、記事中の技術的な記述を Cloudflare と Claude Code の一次ドキュメントで一つずつ突き合わせ直しました。その結果、3 箇所が誤りでした。当時の私の理解が間違っていたということです。該当箇所はそのまま消さず、「当時こう書いた/実際はこうだった」という形で残しています。誤りごと残したほうが、同じ勘違いをしている方の役に立つと考えました。
1. 出発点 — なぜ Claude Code だったのか
「Cursor を使えばいいのでは?」とよく聞かれます。私もそう思っていた時期がありました。
転機になったのは、あるバグ修正でした。コードベースをまたいで影響範囲を自分で把握し、テストを書き直し、PR を出す——この一連の作業を Claude Code は自律的にやり遂げてくれたのです。Cursor はエディタ内補完が得意ですが、Claude Code は「考えながら作業する」ことができます。SaaS 開発のような複雑な依存関係が絡む場面では、この差は大きいです。
もうひとつの理由は、API コストの透明性です。Claude Code は Anthropic API 従量課金なので、何にいくら使っているかが明確です。フラット料金のツールは「使い放題」に見えてコスト感覚が鈍りますが、私はトークン消費を意識しながら開発したかった。個人開発者にとって、コスト感覚は利益率に直結します。
2. プロダクト選定(Day 1〜7)
最初の 1 週間は、プロダクトアイデアの選定に使いました。判断基準は 3 つです。
① 自分が毎日使うもの
外部市場調査より確実な需要確認手段は「自分が困っているか」です。私が選んだのは、複数の App Store プロダクトの売上・レビュー・ランキングを一括で管理するダッシュボードでした。
② Claude Code が得意な技術スタック
Next.js + TypeScript + Stripe + Cloudflare Workers。この組み合わせを選んだのは、Claude Code がこのスタックに非常に精通しており、エラーの自己修正率が高いからです。Ruby on Rails や Django を選んでいたら、学習コストとデバッグコストが跳ね上がっていたと思います。
③ 3 ヶ月で収益化できる複雑さ
「スモールスタートで課金する」設計にしました。完成してから課金するのではなく、最初の有料機能を Day 30 にリリースする計画で逆算しました。
3. MVP 設計 — Claude Code との設計対話(Day 8〜14)
コードを書く前に 1 週間、Claude Code と設計を練りました。設計フェーズでは、実装に入らせず計画だけを立てさせるモード——プランモードを多用しています。
訂正①(2026-08-31)
公開時の本文では、このモードを /architect というコマンドで呼び出すと書いていました。そのようなコマンドは存在しません。正しくは /plan、または対話中に Shift+Tab を押してモードを切り替えます。CLI では Shift+Tab を押すたびに default → acceptEdits → plan と巡回します(Choose a permission mode)。私の手元のメモが古いエイリアスのままだったのだと思います。読んでくださった方に無駄な時間を使わせていたら申し訳ありません。
# 設計フェーズで使ったコマンド例
claude --model claude-opus-4-6 "
以下の要件で Next.js + Cloudflare Workers の設計をレビューしてください。
要件:
- App Store Connect API でデータ取得
- 複数アプリの売上・レビューを統合表示
- Stripe Pro 月額課金(¥580/月)
- 10,000 ユーザーまでスケール可能
懸念点として伝えておきたいのは、App Store Connect API には rate limit があること。
Cloudflare Workers の CPU 時間の上限も考慮に入れてください(無料プランは 1 リクエストあたり 10 ms)。
"この設計対話で気づいた落とし穴が 2 つありました。
落とし穴①: Cloudflare Workers の CPU 時間
App Store Connect から取得した数字をリクエストのたびに集計すると、CPU 時間の上限に触れる。Claude Code の提案は「集計は Cron Trigger + KV にオフロードし、リクエスト時は読むだけにする」でした。この設計変更を Day 8 に決めたおかげで、後からの作り直しを避けられています。
訂正②(2026-08-31)
当時の私は「Workers の CPU 制限は 10ms/request」と、プランを区別せずに書いていました。正確には次のとおりです。
| 項目 | Workers Free | Workers Paid |
|---|---|---|
| HTTP リクエストあたりの CPU 時間 | 10 ms | 既定 30 秒(最大 5 分まで引き上げ可) |
| Cron Trigger あたりの CPU 時間 | 10 ms | 30 秒(1 時間未満間隔)/15 分(1 時間以上間隔) |
さらに重要なのは、fetch() や KV 読み取りの待ち時間は CPU 時間に数えられないという点です(Limits)。つまり「外部 API を何本も叩くから CPU 制限に引っかかる」という私の心配自体が的外れでした。CPU 時間を食うのは、取ってきた JSON を JavaScript 側で舐めて集計する処理のほうです。
有料プランに引き上げる設定はこれだけです。
{
"limits": {
"cpu_ms": 300000 // 既定は 30000(30 秒)
}
}では Cron + KV へのオフロードは無駄だったのかというと、そうではありません。無料プランの 10 ms は現実的にかなり厳しく、Cloudflare 自身が「認証やサーバーサイドレンダリング、大きなペイロードの解析を伴う処理は 10〜20 ms 程度を使う」と書いています。集計を事前計算に寄せる判断は、理由を取り違えたまま結果的に正しかった、というのが正直なところです。
落とし穴②: Stripe Webhook の冪等性
「課金完了 → KV にフラグを立てる」という単純な設計では、Webhook の再送信で重複処理が発生します。Claude Code が指摘するまで、私はこれを見落としていました。冪等キーの設計を最初から組み込んだことで、後でハマる典型的なバグを防げました。
4. 実装フェーズ — モデル使い分けとトークン管理(Day 15〜60)
ここが最もコストに直結するフェーズです。私が確立したルールを公開します。
モデル使い分けの原則
| タスク | モデル | 理由 |
|---|---|---|
| 設計・アーキテクチャ判断 | claude-opus-4-6 | 複雑な判断が必要 |
| 実装・コード生成 | claude-sonnet-4-6 | コスパ最良 |
| 単純なリファクタリング | claude-haiku-4-5 | 高速・低コスト |
| バグ修正(原因特定済み) | claude-haiku-4-5 | 方針が決まっていれば十分 |
表にある claude-opus-4-6 / claude-sonnet-4-6 / claude-haiku-4-5 は、この 90 日間に実際に使っていたモデルです。いずれも現在も有効な ID ですが、その後 Opus 5・Sonnet 5 が出ています。世代が変わっても**「判断は上位モデル、書き取りは中位、機械的な置換は下位」という役割分担の形は変わりません**でしたので、読み替えていただければそのまま使えます。
具体的には、朝の設計セッションだけ Opus を使い、それ以外は Sonnet と Haiku に振り分けました。切り替えを始めた月から請求額ははっきり下がっています。ただし A/B を取ったわけではなく、同じ月に「セッションを短く切る」習慣も始めているため、削減率を数字で申し上げることはできません。効いたのは片方だけかもしれません。
セッション設計の重要性
Claude Code で一番失敗しやすいのが、1 つのセッションを長くしすぎることです。コンテキストが膨らむと:
- 既に決定した設計を「忘れて」別の実装を提案し始める
- 修正のループが増え、無駄なトークンを消費する
- 前の変更を踏まえた提案ができなくなる
私が実践したのは「CLAUDE.md での状態管理」です。各セッションの開始時に、直前のセッションで決定したことを CLAUDE.md に記録し、次のセッションで最初に読み込ませます。
<!-- CLAUDE.md の state セクション例 -->
## 現在の実装状態(2026-03-15 更新)
### 完了済み
- App Store Connect API wrapper(src/lib/asc.ts)
- Cloudflare KV キャッシュ戦略(5分TTL)
- Stripe Webhook 冪等キー実装
### 次のセッションのタスク
- ダッシュボード UI コンポーネントの実装
- recharts でグラフ表示
- [ ] 注意: recharts は Cloudflare Workers では動かない(SSR 禁止)このメモが、セッション間の「文脈の橋渡し」になります。特に「注意点」を記録する習慣が、後のデバッグ時間を大幅に削減しました。
5. 最初の有料ユーザー獲得(Day 30)
計画通り、Day 30 に最初の有料機能をリリースしました。設計上の判断を 1 つ共有します。
「Free → Paid」の摩擦を下げる設計
Claude Code に実装を依頼した際、最初の提案は「登録後に支払い情報を入力させる」フローでした。私はこれを却下し、こう変えました。
無料で使う → 7日間フルアクセス → 8日目から有料機能が制限される → Stripe Checkout に誘導
理由は個人的な体験からです。登録直後にカード情報を求められるサービスは、私自身が離脱しています。まず価値を体験してもらう。
転換率がどう動いたかも書きたいところですが、Day 30 時点の母数は二桁に届いていません。この規模で「◯% から ◯% に改善した」と言うのは、数字の形をした願望です。ですので、ここでは設計の意図だけをお伝えします。効果を測るなら、最低でも数百セッション貯めてからにしてください。
Claude Code での実装時、Stripe Trial Period の設定は 1 行の変更でした。しかし「7 日後に自動課金が始まる」ことをユーザーに明示するメールのタイミング設計——これは Claude Code と何度も対話しながら詰めた部分です。
6. 本番リリースと Cloudflare 運用(Day 60〜90)
Cloudflare Workers + Pages にデプロイしての本番運用で、Claude Code が特に役立ったのはデバッグフェーズです。
エッジ環境特有のエラー対応
本番で発生したエラーのうち、私が自力では原因を特定できなかったものが 3 件ありました。すべて Cloudflare Workers 固有の制約によるものです。
エラー①: Cannot perform I/O on behalf of a different request
claude "以下のスタックトレースを分析してください。
Cloudflare Workers 環境で発生しています。
[スタックトレースをペースト]
このエラーは KV 操作が非同期で分離されたコンテキストで呼ばれた時に起きます。
修正方法を示してください。"Claude Code の回答は即座でした。当時の私はその説明を「waitUntil() を使わずに KV を非同期書き込みしていたから」と受け取り、そのまま本文にも書いています。
訂正③(2026-08-31)
これは原因の取り違えです。このエラーは、あるリクエストのコンテキストで作られた I/O オブジェクト(レスポンスボディ、ストリーム、KV 操作の途中の状態など)を、別のリクエストのハンドラから触ったときに出ます。典型的な作り込みは、リクエスト固有のオブジェクトをモジュールのトップレベル(グローバルスコープ)の変数に置いてしまうことです。isolate は複数リクエストで使い回されるので、次のリクエストが前のリクエストの持ち物に手を伸ばして落ちます。対処は、リクエスト単位の値をグローバルに持たず、引数か env バインディング経由で渡すこと(Workers Best Practices)。
waitUntil() はまた別の役目です。レスポンスを返した後も処理を続けたいときに使うもので、応答後・切断後に最大 30 秒まで実行を延ばせます。私のコードは両方の問題を同時に抱えていて、waitUntil() を足したことで症状が消えたためにそちらが原因だと思い込んだ、というのが実際のところでした。
エラー②: デプロイ時に Worker バンドルのサイズ上限を超えた
これはダッシュボードではなく、同じ時期に触っていた記事配信側の Worker で起きたものです。コンテンツを 1 枚の大きな JSON にまとめてバンドルに同梱していたところ、件数が増えるにつれてデプロイが通らなくなりました。
Claude Code の提案は、メタデータと本文 HTML を分離し、本文は個別ファイルとして静的アセットに出して実行時に取得する設計でした。この作り替えを、コードを生成しながら理由ごと説明してくれたのは助かりました。
なお、上限の実数は次のとおりです。当時の私は「62 MiB」という数字を口伝えのように覚えていましたが、正しくは非圧縮 64 MB のほうで、実務で先に当たるのは gzip 後の値です。
| Worker サイズ | Workers Free | Workers Paid |
|---|---|---|
| gzip 圧縮後 | 3 MB | 10 MB |
| 圧縮前 | 64 MB | 64 MB |
自分のバンドルが今どのくらいかは、デプロイせずに確認できます。
wrangler deploy --outdir bundled/ --dry-run
# Total Upload: 259.61 KiB / gzip: 47.23 KiBこの gzip: の数字が 3 MB(有料なら 10 MB)に近づいてきたら、設定ファイルや静的データをバンドルから追い出す時期です。
90 日間のコストと収益
公開できる範囲で数字を共有します。
| 項目 | 金額 |
|---|---|
| Claude Code トークンコスト(90日・請求書の実額) | 約 ¥45,000 |
| Cloudflare Workers(無料プランのまま運用) | ¥0 |
| Stripe 手数料 | 売上に対する変動費 |
| 90日時点の MRR(月次経常収益) | 非公開 |
¥45,000 は請求書に残っている実額です。内訳は最初の 1 ヶ月が ¥20,000 超で、そこから月 ¥10,000 前後に落ち着いています。何がどれだけ効いたかの切り分けはできていません。同じ時期にモデルの使い分けと CLAUDE.md での状態管理を同時に始めてしまったからです。切り分けたい方は、片方ずつ入れて 1 ヶ月ごとに請求額を見てください。私は最初にそれをやりませんでした。
MRR を非公開にしているのは、隠したいからではなく、この規模の数字を出すと「90 日でここまで行ける」という誤った期待値をつくってしまうためです。プロダクトも読者層も違えば、桁ごと変わります。
7. 振り返り — Claude Code との 90 日で学んだこと
やってよかったこと
設計に時間をかけたこと。Day 1〜14 の設計フェーズで Claude Code と丁寧に対話したおかげで、後の手戻りが最小になりました。実装フェーズで「根本から設計を変える」ことは一度もありませんでした。
失敗を記録し続けたこと。CLAUDE.md の「注意点」セクションに失敗パターンを書き続けたことで、同じミスを繰り返しませんでした。Claude Code は前のセッションを覚えていませんが、ドキュメントは覚えています。
やらなければよかったこと
完璧主義。UI のデザインに時間をかけすぎました。最初の有料ユーザーは UI のきれいさではなく「自分の問題を解決できるか」で判断します。Day 20 に気づいてからは、「動く最小構成」を優先する意思決定に変えました。
1 つのセッションを長く続けること。これは本当に痛い目を見ました。8 時間のセッションの末に、Claude Code が最初の設計と矛盾するコードを生成し始め、すべてロールバックしたことがあります。今は 2 時間を目安にセッションを切っています。
90 日という期間は、「SaaS を作れるかどうか確認する」には十分でした。到達できたのは Claude Code のおかげだけではなく、個人開発者として積み上げてきた判断力もあります。実装速度が何倍になったかは、正直なところ測っていません。倍率を書けば説得力は出るのでしょうが、手元にない数字を書きたくないのです。確かなのは、「何を作るか」「いつ切り上げるか」の判断は依然として人間の仕事だ、ということだけです。
そしてこの記事を書き直して、もうひとつ確かになったことがあります。AI が即答してくれた説明ほど、後で一次情報に当てるべきだ、という点です。今回訂正した 3 箇所は、いずれも Claude Code の回答そのものというより、私がその回答を都合よく要約して覚えてしまった結果でした。症状が消えたことと、原因を理解したことは違います。
次に試すなら、30 日のミニ SaaS を提案します。30 日で「誰かに課金してもらう」を目標にすると、設計も実装も優先順位が勝手に決まります。そしてもし公開するなら、技術的な断定を書いた箇所には、その場でドキュメントの URL を添えておいてください。数ヶ月後の自分が助かります。私はそれを怠って、この訂正に半日かけました。
お読みいただきありがとうございました。