
個人開発・スタートアップ向けのスタック:小さく作って、運用を軽くする
少人数で作って、少人数で運用し続けるための技術選びを、実際に動かしているWebアプリの構成(React Router、Cloudflare Workers、D1、Clerk)を例に整理する。
小さなチームのスタックは、「速さ」より「運用の軽さ」で選びます。サーバーを持たない、認証は任せる、デプロイは自動、本番だけ人が確認する。この4つを軸にすると、少人数でも長く回せます。
小さなチームが技術を選ぶ基準
大きな会社の技術選びは、「何千人が使っても耐えるか」から考えます。個人開発や、創業直後のスタートアップは、別の問題を抱えています。人が少なく、時間が足りず、夜中に障害が起きても自分で直すしかありません。
この記事は、実際に動かしている小さなWebアプリ「PAIBOT.app」の構成を例に、少人数で作って、運用し続けるための選び方を整理します。選ぶときの基準は、次の5つです。
- サーバーを持たない:OSの更新や、サーバーの再起動、容量の心配を、自分で抱えない
- 固定費が小さい:使われなければ、ほとんどお金がかからない形から始められる
- 任せられるものは任せる:認証や、決済、メールなど、間違えると危ないものは、専門のサービスに任せる
- テストとデプロイが自動:少人数ほど、手作業の確認で時間を失う
- 後から動かせる:特定の会社にだけ縛られない作りにしておく
この記事の構成は、一つの例です。正解ではありません。サービスの機能、料金、無料枠は変わるので、使う前に、各社の公式ドキュメントで確認してください。
全体の構成
PAIBOT.appは、ブラウザで使える小さなツール集に、ログインとお気に入りの機能を足したWebアプリです。構成は次のとおりです。
- フレームワーク:React Router(フレームワークモード)。サーバー側で画面を作り(SSR)、ブラウザでは操作できる部品として動く
- 実行環境:Cloudflare Workers。自分のサーバーはなく、世界中の拠点で、リクエストのたびにコードが動く
- データベース:Cloudflare D1(SQLite互換)。ORMはDrizzleを使う
- 認証:Clerk。ログイン画面も、パスワードの保存も、自分では作らない
- AI:Workers AIをバインディングで呼ぶ。外部のAIサービスのAPIキーを持たずに済む
- レート制限:Workersのレート制限機能で、IPごとの回数を絞る
各層の選択と理由
| 層 | 選んだもの | 理由 |
|---|---|---|
| 画面 | React Router(SSR) | 検索エンジンに読まれる画面を、サーバー側で作れる。ルーティングとデータ取得が、1つの仕組みにまとまる |
| 実行環境 | Cloudflare Workers | サーバーの運用が要らない。使われない時間は、ほぼお金がかからない形から始められる |
| データ | D1 + Drizzle | 別のDBサーバーを立てなくてよい。型のあるクエリが書ける。スキーマの変更はマイグレーションで管理する |
| 認証 | Clerk | 認証は、自作すると間違えやすく、間違えたときの被害が大きい。専門のサービスに任せる |
| 国際化 | use-intl | 日本語、英語、中国語を、メッセージのファイルで管理する |
| テスト | Nodeの標準テスト + Playwright | 計算などの部品は軽い単体テスト、画面はブラウザで1本の流れを確かめる |
| 設定の管理 | Wrangler + Terraform | 同じものを2か所で管理しない。アプリに近いものはWrangler、アカウント全体の設定はTerraform |
「Workersだから速い」「D1だから安い」ではなく、運用に手間がかからないことを理由にしています。
作る順番の工夫:ツール1つ、フォルダ1つ
ツールが増えても散らからないように、新しいツールは、1つのフォルダに、自分の部品をすべて入れる決まりにしています。画面、ロジック、単体テスト、ブラウザのテストが同じフォルダにあり、共通の一覧に登録するだけで、トップページの検索や、サイトマップにも反映されます。
- 変更が影響するツールだけ、ブラウザのテストを動かす(共通の部品を変えたときは全部動かす)
- 共通の確認(3つの言語で開ける、エラーが出ない、スマホ幅に収まる)は、テストを書かなくても、全ツールに自動で効く
- 環境に依存するコード(Cloudflare専用の機能)は、サーバー専用のファイルに閉じ込める
最後の点は、「後から動かせる」ための工夫です。環境に依存する部分を薄い層にしておくと、実行環境を変えるときの影響が小さくて済みます。
デプロイの流れ
少人数のチームでは、デプロイを人の手でやるほど、ミスが増えます。PAIBOT.appでは、次の流れにしています。
- 変更を出す(PR)たびに、型の検査、単体テスト、ビルド、ブラウザのテストを自動で動かす
- メインに入ったら、開発環境へ自動でデプロイする。開発環境は、Cloudflare Accessで、許可した人だけが開けるようにしている
- 本番は、人が手動で実行する。その変更が開発環境で成功していることを、本番の手順の中で確認する。問題があれば、タグを指定して、以前の版に戻せる
- データベースの変更(マイグレーション)も、本番のデプロイの手順に含める
本番だけ手動にしているのは、「自動で全部が本番に出る」のが怖いからです。人が確認するステップが、手動の実行そのものです(当時は、チームの承認機能が、使っていたプランにはなかったため、この形にしました)。
実際に踏んだ罠
最初から今の構成だったわけではありません。このアプリは、最初はNext.jsを、ベータ版のアダプターでCloudflare Workersに載せて作りました。動きましたが、前例の少ない組み合わせで、認証ライブラリの読み込みや、国際化ライブラリの二重読み込みなど、接続部分で何度か詰まりました。結果として、Workersで素直に動く、React Routerに移しました。
ここから言えることは、次のとおりです。
- 本番には、前例の多い組み合わせを選ぶ:ベータ版の部品が間に入ると、不具合の原因が、自分のコードか部品か分からなくなる
- 詰まったら、二重のモジュールを疑う:同じライブラリが2つの経路で読み込まれると、片方の状態がもう片方に見えない。エラーの場所は、ライブラリの内部に出る
- 移行できる形を保つ:境界を薄くしておいたので、大きな書き換えではなく、移行で済んだ
個人開発とスタートアップで、変えるところ
| 観点 | 個人開発 | 創業直後のスタートアップ |
|---|---|---|
| 優先すること | 作り続けられること | 検証の速さと、後から直せること |
| 認証 | 任せる(自作しない) | 任せる。企業向けのログイン(SSO)が要るか早めに確認する |
| データベース | 小さく始める。1つにまとめる | 将来の移行を想定して、DBへのアクセスを1か所にまとめる |
| 費用 | 無料枠から始める | 無料枠が尽きる境目と、その後の料金を、先に見積もる |
| 監視 | エラーを見られる最低限 | 障害の連絡と、対応の担当を決める |
| 人が増えたとき | あまり考えない | テストと、デプロイの自動化が、人を増やす前提になる |
選ぶときの注意
- サービスへの依存:便利な機能ほど、そのサービスに寄ります。依存の入り口を、薄い層にまとめておくと、動かしやすい
- 無料枠の落とし穴:無料枠が大きくても、条件や上限は変わる。使い方が増えたときの料金を、早めに見ておく
- データの置き場所:ユーザーのデータをどこに置くか(地域、法令)は、後から変えにくい。早めに決める
- 任せられないもの:権限の設計(誰が何を見られるか)は、サービスに任せても、設計は自分の仕事
確認リスト
- 自分でOSやサーバーを管理しなくてよい構成になっているか
- 認証や決済を、自作していないか
- 変更を出すたびに、テストが自動で動くか
- 本番へ出す前に、人が確認するステップがあるか。以前の版に戻す手順があるか
- データベースの変更を、記録して管理しているか
- 環境依存のコードが、1か所にまとまっているか
- 無料枠の上限と、超えたときの料金を調べたか
- 障害のときに、誰が気づいて、誰が直すかを決めたか