Next.js 15とClaude Codeを使えば、認証・DB・CRUD・デプロイまで揃ったSaaSの雛形が、初心者でも2時間で動く。この記事は完全ノーカットの手順書だ。題材は「シンプルなメモ管理SaaS」。ユーザー登録してログインし、自分のメモをCRUDし、本番URLで動くところまで持っていく。
前提は次の2つだけ。
- Node.js 20以上(
node -vで確認) - Claude Codeがインストール済み(
claude --versionで確認)
使うスタックはNext.js 15(App Router) + Clerk(認証) + Neon(PostgreSQL) + Drizzle ORM + Vercel(デプロイ)。全て無料枠で足りる。
ステップ1: プロジェクト作成(所要5分)
npx create-next-app@latest memo-saas --typescript --app --tailwind --eslint --src-dir --import-alias "@/*"
cd memo-saas
インタラクティブな問いに対しては全てデフォルト(Yes)で進めて構わない。完了したらnpm run devでhttp://localhost:3000が開くことを確認する。
ステップ2: CLAUDE.md を書く(所要5分)
プロジェクトルートにCLAUDE.mdを作る。これはClaude Codeが常時参照する「プロジェクトの憲法」だ。雑に書くと雑な出力が返ってくる。
# memo-saas
## 概要
認証付きのメモ管理SaaS。ユーザーは自分のメモのみ閲覧・編集できる。
## 技術スタック
- Next.js 15 (App Router, Server Actions)
- TypeScript (strict)
- Clerk (認証)
- Neon (Postgres)
- Drizzle ORM
- Tailwind CSS
- Vercelデプロイ
## ルール
- `any`型の使用を禁止する
- DBアクセスは必ず`src/db/`配下のモジュール経由
- 認証チェックは各Server Actionの冒頭で`auth()`を呼ぶ
- UIコンポーネントは`src/components/`、ページは`src/app/`
このファイルがあるだけでClaude Codeの出力精度が体感で3倍変わる。
ステップ3: Clerk で認証(所要20分)
Clerkの無料枠は月間アクティブユーザー10,000人まで。個人開発では事実上無限だ。
Clerkのダッシュボードでアプリケーションを作成し、Publishable KeyとSecret Keyをコピーする。.env.localに貼る。
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_xxxxx
CLERK_SECRET_KEY=sk_test_xxxxx
ここからClaude Codeの出番。以下をそのまま投げる。
Next.js 15 App Routerに
@clerk/nextjsを導入してほしい。手順は次の通り。1) パッケージインストール、2)src/middleware.tsにclerkMiddlewareを設定、3)src/app/layout.tsxを<ClerkProvider>でラップ、4) サインインページとサインアップページを/sign-inと/sign-upにキャッチオールルートで作成、5)/dashboardを認証必須ページに設定。.env.localは既に設定済み。
Claude Codeが5ファイル前後を生成したら、npm run devで/sign-upにアクセスし、アカウント作成 → /dashboardリダイレクトまで動くことを確認する。
ステップ4: Neon + Drizzle で DB接続(所要25分)
Neonは無料枠で0.5GB、分岐DB5個まで使える。プロジェクトを作成し、接続文字列(postgres://...)をコピー、.env.localに追記する。
DATABASE_URL=postgres://user:password@ep-xxxx.ap-southeast-1.aws.neon.tech/neondb?sslmode=require
Claude Codeに次を投げる。
Drizzle ORMをセットアップしてほしい。1)
drizzle-ormとdrizzle-kitとpostgresをインストール、2)src/db/schema.tsにmemosテーブル(id: uuid主キー、userId: text not null、title: text not null、body: text、createdAt: timestamp default now)を定義、3)src/db/index.tsにDBクライアントを初期化、4)drizzle.config.tsを作成、5)npm run db:pushでスキーマをNeonに反映できるようにpackage.jsonにスクリプトを追加。
生成後、以下を実行する。
npm run db:push
Neonのダッシュボードでmemosテーブルが作成されていれば成功だ。
ステップ5: CRUD ページを作る(所要40分)
ここがメインディッシュ。Claude Codeに次のプロンプトを投げる。具体的に書けば書くほど品質が上がる。
/dashboardページにメモのCRUDを実装してほしい。要件は以下。
- 認証必須。
auth()でuserIdを取得し、無ければ/sign-inにリダイレクト- Server Actionsで実装すること(API Routeは使わない)
- ファイル構成:
src/app/dashboard/page.tsx(一覧と新規作成フォーム)、src/app/dashboard/actions.ts(createMemo, deleteMemo, updateMemo)- Server Actionの冒頭で必ず
auth()を呼び、userIdが一致するメモのみ操作可能にする- フォームは
useFormStatusでpending状態を表示- 削除ボタンは
<form action={deleteMemo.bind(null, memo.id)}>パターン- Tailwindでシンプルかつ読みやすいUIに(max-w-2xl中央寄せ、カード型)
CLAUDE.mdのルールを守ること。特に
any禁止と認証チェック必須。
生成されたコードを読み、Server Action冒頭のauth()呼び出しとeq(memos.userId, userId)の条件が両方入っていることを必ず確認する。片方でも抜けると他人のメモが見える脆弱性になる。
// src/app/dashboard/actions.ts の期待形
"use server";
import { auth } from "@clerk/nextjs/server";
import { db } from "@/db";
import { memos } from "@/db/schema";
import { and, eq } from "drizzle-orm";
import { revalidatePath } from "next/cache";
export async function createMemo(formData: FormData) {
const { userId } = await auth();
if (!userId) throw new Error("Unauthorized");
const title = String(formData.get("title") ?? "").trim();
if (!title) return;
await db.insert(memos).values({ userId, title, body: String(formData.get("body") ?? "") });
revalidatePath("/dashboard");
}
export async function deleteMemo(id: string) {
const { userId } = await auth();
if (!userId) throw new Error("Unauthorized");
await db.delete(memos).where(and(eq(memos.id, id), eq(memos.userId, userId)));
revalidatePath("/dashboard");
}
ステップ6: Vercel にデプロイ(所要15分)
GitHubにプッシュし、Vercelのダッシュボードで「Import Project」→リポジトリ選択。環境変数としてNEXT_PUBLIC_CLERK_PUBLISHABLE_KEY、CLERK_SECRET_KEY、DATABASE_URLの3つを設定する。
git init
git add .
git commit -m "initial commit"
git remote add origin https://github.com/yourname/memo-saas.git
git push -u origin main
Vercelは自動でビルド&デプロイし、2分後にhttps://memo-saas-xxx.vercel.appが発行される。この時点でサインアップ→メモ作成→削除が本番で動く。
ClerkのダッシュボードでProduction環境用のPublishable Key/Secret Keyを改めて発行し、Vercelの環境変数に本番値として設定するのを忘れないこと。開発用キーのままだとメール認証で詰まる。
要点まとめ
- Claude Codeへの指示は「CLAUDE.md + 具体的なファイル構成 + セキュリティ要件」の3点セットで渡すと精度が跳ね上がる
- 認証チェックとユーザーIDによるフィルタは、Server Actionの先頭で必ず両方入れる
- 無料枠(Clerk + Neon + Vercel)だけで本番稼働するSaaSが組める
- 2時間のうち、実はコードを書くのは15分程度で、残り1時間45分は「Claude Codeに適切に指示する」「生成結果を読んで検証する」時間になる
このテンプレートを下敷きに、memosテーブルを自分のドメインに置き換えれば、週末で新しいSaaSを1本ずつ立ち上げられる。