Vercel + Next.js 本番運用の実務ノート (日本・2026 年版)
ClearNets では clearnets.org・merci.clearnets.org・kotsukotsu.clearnets.org・kotodama.clearnets.org・oshitabi-clearnets.vercel.app の 5 サイトすべてを Vercel + Next.js 15 で運用しています。本記事は「Vercel の紹介」ではなく「実際に 1 年以上本番で回してみて何が効き、何がハマったか」を、コマンド・設定ファイル・失敗ログ付きで整理した実務ノートです。AWS Amplify / Cloudflare Pages / Netlify を検討中の方、あるいは既に Vercel を使っていて Preview デプロイ・Cron・Domain 移行で悩んでいる方に向けて書きました。
1. なぜ Vercel か / どこで妥協するか
Vercel を選んだ理由は 3 つに集約されます。第一に Next.js との統合が公式レベルで完結している こと。ISR / Server Component / Server Action / Middleware / Image Optimization など、 Next.js の最新機能が Vercel では設定 0 で動きます。他ホスティングだと 「動くには動くが Image Optimization が壊れる」「middleware が Edge にデプロイされない」など細かい罠が絶えず、少人数で回すには時間コストが 重すぎます。第二に Preview デプロイが git push で自動 で立ち上がること。第三に 無料 Hobby プランで個人プロダクト 5 本まで実質回せる 点です。
一方で妥協する必要がある点も明確にしておきます。(a) Serverless Function の実行時間は Hobby 10 秒 / Pro 60 秒 / Enterprise 900 秒。バッチ処理は Vercel の外 (Cloud Run / GitHub Actions) に逃す方針を最初から取っておく。 (b) Bandwidth 課金 が意外と効く。Hobby 100 GB / 月、 Pro 1 TB / 月。画像 heavy な EC / メディア系だと Pro でも足りない事例が あるので、静的アセットは Cloudflare R2 に逃す設計を最初から想定。(c) リージョンは「関数が動くリージョン」と「エッジ配信のリージョン」で別。 DB は東京 (nrt1) 固定でも、静的配信は世界エッジ、と分離して考える。
ClearNets の 5 プロダクトはこの制約に全部収まる規模なので Vercel で回して いますが、動画配信 / 100k+ MAU の EC / 30 秒超の PDF 生成などは 別プラットフォーム併用が現実的です。
2. Git 連携 → 自動デプロイ → Preview の全体像
Vercel の心臓部は「GitHub の main ブランチが本番、それ以外の branch が Preview」というシンプルな規約です。vercel link で リポジトリを Project に紐付けた瞬間から、以下が自動化されます。
- main への push: 本番 (Production) にデプロイ、 Production Domain (例:
www.clearnets.org) を張替え。 Rollback は前バージョンに 1 クリックで戻せる。 - feature ブランチへの push: Preview デプロイ、 ユニーク URL (例:
clearnets-home-git-feature-x-clearnets-prod.vercel.app) が発行される。PR コメントに Vercel Bot が URL を自動投稿。 - PR ごとに独立した env: Preview 環境の 環境変数は「Preview」スコープで別管理。本番 DB を Preview からは 触らせない設計にできる (Neon の branch DB と組合せると完璧)。
ClearNets では ここに追加で 「main ブランチは保護、必ず PR 経由」 を GitHub Ruleset で強制しています。個人開発でも 「main に直 push で本番事故」は普通に起きるので、たとえ 1 人でも PR 経由 + Preview で目視確認 + squash merge の 3 点セットは徹底する 価値があります。
# GitHub Ruleset (main 保護) — 個人開発でも入れる - main ブランチへの直 push を全員禁止 (自分も含む) - PR merge には最低 1 approval (self-approve 許可) - CI (pnpm lint, tsc, test) 全緑必須 - Vercel Preview デプロイ URL の目視確認を PR チェックリストに含める
3. Preview デプロイの正しい使い方 — Neon Branch DB と組合せる
Preview の URL だけ立てても、DB が本番と共通だと「Preview 上の破壊的 migration が本番を壊す」事故が普通に起きます。ClearNets では Neon の branch DB を PR 毎に自動生成 して、 Preview 環境変数の DATABASE_URL をそれに差し替える パイプラインを組んでいます (詳細は Neon 記事参照)。
Preview 環境で特に気をつけるべき環境変数の分離:
DATABASE_URL: Preview では branch DB を指す。本番 DB は 絶対に見せない。STRIPE_SECRET_KEY: Preview では test mode key (sk_test_...)、本番では live key (sk_live_...)。この分離を忘れると Preview の「テストのつもりの決済」が 本番 charge になる。RESEND_API_KEY: Preview 用に別 API key を発行して、 送信先を@clearnets.orgのみに絞る。Preview から不特定 多数にメール送信事故を防ぐ。NEXT_PUBLIC_*: bundle に露出するので Preview / Production 両方に設定必須。忘れると Preview で機能が undefined になる。
Vercel の UI で環境変数を追加する時、Environment 選択で「Production / Preview / Development」の 3 チェックが独立してつけられます。ここで Production だけにチェックした変数は Preview では undefined になるので、 Preview で NoMethodError が出たら大体これです。
4. Rollback の 3 通りのやり方
本番デプロイ後にバグ発覚した時の Rollback パスを 3 通り整理します。 深夜 3 時に慌てないよう、日頃から手順化しておく。
- Vercel Dashboard から Instant Rollback: Deployments タブから直前の Production Deployment を選び「Promote to Production」。 10 秒で切り戻る。コード変更は伴わないので、GitHub の main は壊れたままなのを忘れずに (次のステップで git revert する)。
- git revert + push: 該当 commit を
git revertして main に push。Vercel が自動でその revert commit を Production デプロイして正常化。履歴が残るので事故分析に向く。 ClearNets はこれを標準運用にしています。 - CLI から特定 deployment を promote:
vercel promote <deployment-url>で任意の過去 deployment に切戻せる。CI / スクリプト自動化向き。
ClearNets が実際に踏んだ Rollback 事例 (2026-06 頃): OSHITABI のデプロイでnext-intl plugin の wire ミスで全 route 500 になった時、 Vercel Dashboard の Instant Rollback で 15 秒で戻し、そのあと落ち着いて git revert → 修正 PR を出す、という段取りで復旧しました。目視確認と Instant Rollback は本番運用で最も価値のある「1 分で戻せる」武器です。
5. Domain 移行 — nameserver vs DNS-only の選択
Vercel に独自ドメインを繋ぐ方法は大きく 2 通り。ClearNets は Cloudflare を DNS-only (proxy off) で挟む 構成に 統一しています。
- 方法 A: Vercel nameserver 直: Vercel Dashboard で Domain 追加 → 指示された NS レコードを Registrar に設定。楽だが Cloudflare の DNS / R2 / Zero Trust / Turnstile などを併用したい時に 障害になる。ClearNets はこの方式は使っていない。
- 方法 B: Cloudflare 経由 (CNAME + A レコード): Cloudflare を nameserver にしたまま、対象サブドメインを DNS-only (proxy off / グレー雲) で Vercel に向ける。 Vercel の SSL 発行が Let's Encrypt 経由で通るし、Cloudflare の 他サービスも併用できる。ClearNets の全 5 サブドメインはこの構成。
Cloudflare Proxy (オレンジ雲) を ON にしたまま Vercel に向けると、 Vercel 側の SSL 発行に失敗するか、Edge Function の Real IP が取れなくなる (Cloudflare の CF-Connecting-IP header を明示的に読む必要がある) など 小さい罠があるので、まずは Proxy OFF で開始するのが安全です。
# Cloudflare DNS レコード例 (kotsukotsu.clearnets.org を Vercel に) Type Name Content Proxy CNAME kotsukotsu cname.vercel-dns.com DNS only # Vercel Dashboard の Project Settings > Domains で # "kotsukotsu.clearnets.org" を追加すると自動で SSL 発行
Domain 移行時にハマった事例: 6 月に OSHITABI の Production URL を oshitabi-clearnets.vercel.app から oshitabi.clearnets.org に切替検討した時、sitemap.xml / canonical / og:image URL が全部 vercel.app 固定で埋め込まれていて SEO が二重登録になる危険がありました。対策として STABLE_PRODUCTION_URL を export const で 1 ヶ所に集約 → 全参照はそれ経由、 にリファクタして解決。Domain 移行時に 1 ヶ所差替えで完結する設計は 後々効きます。
6. Vercel Cron — 便利だが 5 つの罠
vercel.json に定義するだけで cron が動く便利機能ですが、 実運用で踏んだ罠を 5 つ記録。
// vercel.json
{
"crons": [
{ "path": "/api/cron/aggregate-daily", "schedule": "0 15 * * *" },
{ "path": "/api/cron/send-reminders", "schedule": "0 22 * * *" }
]
}- Timezone は UTC 固定: 上記の
0 15 * * *は UTC 15:00 = JST 24:00 (深夜)。日本時間で 考えたいときは +9 時間ずらして UTC に書く。TZオプションは無い。 - Hobby プランは 1 日 2 回まで: Pro プランで
* * * * *(毎分) も可能。Hobby で毎分 cron を書くと 「デプロイ時は通るが動かない」状態になる。 - 認証必須: Vercel Cron からのリクエストには
Authorization: Bearer <CRON_SECRET>が付く。API Route 側で verify しないと外部から叩き放題。 - 10 秒 (Hobby) / 60 秒 (Pro) の関数タイムアウト: cron でも同じ制約。重い集計は「1000 件ずつ処理して次回に続きを」 という chunk 化が必須。
- 失敗時のリトライは無い: cron 失敗はログに残るだけで 自動リトライしない。UptimeRobot などで「cron が動いた痕跡が DB にあるか」を別ルートで監視する必要あり。
// app/api/cron/aggregate-daily/route.ts
import { NextRequest, NextResponse } from "next/server";
export async function GET(req: NextRequest) {
const auth = req.headers.get("authorization");
if (auth !== `Bearer ${process.env.CRON_SECRET}`) {
return NextResponse.json({ error: "unauthorized" }, { status: 401 });
}
// 1000 件 chunk で集計
const chunk = await aggregateNextChunk({ limit: 1000 });
return NextResponse.json({ processed: chunk.length });
}7. Edge Function vs Node Runtime — どちらで書くか
Next.js 15 の API Route / Server Component / Server Action は export const runtime = 'edge' か 'nodejs' を選べます。判断基準を整理:
- Edge Runtime を選ぶ場面: (a) 世界中から低レイテンシで 叩かれる API (地理的分散が価値)、(b) 認証 middleware / A/B test 振り分けなど「軽くて高頻度」なもの、(c) Neon HTTP driver / Upstash Redis / Cloudflare KV など HTTP ベースの外部 API のみ叩く場合。
- Node Runtime を選ぶ場面: (a) Stripe SDK / Sentry SDK など Node.js 特化ライブラリを使う場合、(b) DB トランザクション (Neon Pool WS / node-postgres) が必要、(c)
node:cryptoの hmac / pbkdf2 など Web Crypto では 性能が出ない処理、(d) 60 秒フルに使いたい重処理 (Pro プラン)。
Edge Runtime の落とし穴: process.env が build time 評価になるので runtime での動的な env 読取りができない、 fs は使えない、Node の built-in module (crypto, buffer) は Web 標準 API に書き換え必要。「動くはず」で Edge 化すると build は通っても runtime error になるパターンが多いので、テスト環境で 必ず curl 叩いてから本番デプロイ。
8. Vercel Analytics / Speed Insights の効かせ方
Vercel Analytics は「ページビュー / ユニークビジター / 経路」を計測、 Speed Insights は「Core Web Vitals (LCP / CLS / INP) の実測値」を 計測します。両方合わせて月間 25k イベントまで Hobby 無料。
// app/layout.tsx
import { Analytics } from "@vercel/analytics/next";
import { SpeedInsights } from "@vercel/speed-insights/next";
export default function RootLayout({ children }) {
return (
<html lang="ja">
<body>
{children}
<Analytics />
<SpeedInsights />
</body>
</html>
);
}GA4 との使い分け: Vercel Analytics は「早く手軽に基本」、 GA4 は「詳細な流入元 / コンバージョン設定」。ClearNets は両方入れて いますが、日常ダッシュボードは Vercel Analytics、月次分析は GA4 と 使い分けています。Vercel Analytics は Cookie 不要 (Privacy-friendly) なので EU 圏の Cookie Consent 対応が要らないのが利点。
Speed Insights の Real User Monitoring (RUM) は本番で価値が出ます。 Lighthouse の合成計測より、実ユーザーの実端末 (5 年前の Android / 遅い 4G) での LCP がわかるので、「日本で LCP p75 = 2.4s」など 地域別・端末別のボトルネックが数字で見える。ClearNets の Merci LP は初回 Speed Insights 導入で LCP 4.2s と出て、Image Optimization と priority prop の付け忘れが判明して 1.9s に改善しました。
9. Vercel KV / Blob Storage — 料金と使いどころ
Vercel KV (Upstash Redis の wrap) / Vercel Blob (Cloudflare R2 相当) は Vercel Dashboard から 1 クリック追加できて、環境変数も自動注入 される点は楽です。ただし料金は以下:
- Vercel KV (Hobby): 30k command / 月、256 MB storage まで無料。超過は Pro プラン契約 + Upstash 従量。Rate limiting / セッションキャッシュ用途で 30k は「小規模プロダクトなら足りる」 レベル。
- Vercel Blob (Hobby): 5 GB storage + 10 GB 転送/月 まで無料。ユーザーアップロード画像・PDF 生成物置き場に。プロダクト 規模が拡大したら Cloudflare R2 (エグレス 無料) に逃す判断。
ClearNets の実運用: Rate limiting は Vercel KV で @upstash/ratelimit 使用、Blob は使わず Supabase Storage (Kotodama) と Cloudflare R2 (OSHITABI 画像) を用途別に使い分け。 「エグレスが月 100 GB を超えそう」な媒体系は R2 一択、それ以外は どっちでも良いです。
// Vercel KV で rate limit (1 IP あたり 60 req/min)
import { kv } from "@vercel/kv";
import { Ratelimit } from "@upstash/ratelimit";
const ratelimit = new Ratelimit({
redis: kv,
limiter: Ratelimit.slidingWindow(60, "1 m"),
});
export async function POST(req: Request) {
const ip = req.headers.get("x-forwarded-for") ?? "anon";
const { success } = await ratelimit.limit(ip);
if (!success) {
return new Response("Too Many Requests", { status: 429 });
}
// 処理続行
}10. 環境変数管理と Secrets ローテ手順
Vercel の環境変数は Production / Preview / Development の 3 スコープ独立 で管理されます。CLI の vercel env pull で ローカルに .env.local として同期できます (Development スコープが優先)。
# ローカル開発用の env を Vercel から取得 vercel env pull .env.local # CI から本番 env を上書き vercel env add DATABASE_URL production < db_url.txt # 特定 env を削除 vercel env rm STRIPE_SECRET_KEY production
Secrets ローテ手順 (Stripe key を例に): (1) Stripe Dashboard で新 key を発行、(2) Vercel で STRIPE_SECRET_KEY の値を新 key に上書き、(3) Vercel 再デプロイ (env 変更は自動再デプロイされない仕様)、(4) 動作確認 (Webhook 受信 + 決済 1 件テスト)、(5) 旧 key を Stripe Dashboard で Revoke。順番を 「新 key 追加 → デプロイ確認 → 旧 key 削除」 にしないと、旧 key で動いてる Webhook / cron が瞬断します。
Secrets を GitHub リポジトリに間違って push した事故対処: (a) 該当 secret を即 Revoke、(b) git filter-repo で履歴から削除 (force push)、(c) GitHub > Settings > Secret scanning のアラートを Resolve、(d) 全 collaborator に fresh clone を通知。過去に AWS key を 誤 push した事故で Secret scanning が 2 時間以内に検知 → 実害 0 で 済みました。GitHub の Secret Scanning + Push Protection は必ず ON に。
11. 本番トラブル 5 事例と教訓
ClearNets が実際に遭遇した Vercel + Next.js 本番トラブルを 5 つ、 原因と復旧手順で整理します。全部再現しうる典型パターンです。
- 事例 1: Edge Middleware の環境変数が undefined (2026-05)
症状: 認証 middleware が全 route で 500。
原因:process.env.AUTH_SECRETを middleware で読んでいた が、Edge Runtime では build time 評価 のため Vercel の env に「Edge Config」経由で書き込む必要があった。
対処:NEXT_PUBLIC_*接頭辞にする か、Edge Config API 経由で読むように書換え。今後は「middleware から env 参照する時は Edge Config を経由」を規約化。 - 事例 2: Cron が動かない (2026-06)
症状: 日次集計 cron が 3 日連続で動作 0。
原因:vercel.jsonのscheduleを JST の 22:00 のつもりで0 22 * * *と書いていたが、これは UTC 22:00 = JST 07:00。日中で見逃してた。
対処: UTC に変換し0 13 * * *に修正 (JST 22:00)。 コメントで// JST 22:00 = UTC 13:00を明記。 UptimeRobot で cron endpoint を別途 keep-alive ping しつつ動作痕跡を 監視する構成に変更。 - 事例 3: Image Optimization が課金爆発 (2026-04)
症状: 月末に Vercel の Image Optimization Cost が予算警告。
原因: Blog OGP 画像を<Image src="..." fill />で表示、size prop 未指定で 3840x3840 のフル解像度 が生成されまくっていた。
対処:sizes="(max-width: 768px) 100vw, 800px"を全 Image に付与、Blog OGP は静的 og-image.png (1200x630) を 事前生成して<img>で表示。翌月の課金は 0 に。 - 事例 4: Preview デプロイで環境変数が Prod と混線 (2026-07)
症状: Preview URL で「テストのつもりの Stripe 決済」が本番 charge になった (幸い 100 円のテスト決済で発覚)。
原因:STRIPE_SECRET_KEYを「All Environments」で 設定していて、Preview でも live key が使われていた。
対処: Production / Preview / Development をスコープ分けし直し、 Preview / Development にはsk_test_*を、Production にのみsk_live_*を設定。以降は「All Environments 禁止、必ずスコープ明示」を規約化。 - 事例 5: Vercel デプロイ「Could not retrieve Project Settings」で fail (2026-06-29)
症状:deploy-web-prod.ymlworkflow が全部 fail、 本番 6/8 状態のまま数日ロック。
原因:VERCEL_TOKENの scope が team ではなく個人 のままだった。--scopeflag を消しても復旧せず、Vercel Dashboard で新 team scope token を発行し直しで解消。
対処: Token は Team 発行かつ Machine User 名義、有効期限 90 日 設定 + カレンダー通知でローテ、を規約化。
12. まとめ — Vercel + Next.js は「小さく始めて Pro に上げる」曲線
Vercel + Next.js の魅力は、Hobby プラン 5 プロダクトを ¥0 で回しながら、 トラフィックが伸びたら Pro ($20/月) にワンクリックでアップグレードできる 料金曲線にあります。個人開発 / 少人数チームには「収益前は無料、収益後は 課金」の理想的な形。ClearNets の 5 プロダクトはすべて Hobby で回っていて、 Pro に上げるのは「MAU 数千 + Cron が毎分必要 + 60 秒関数が必要」に なった時、と決めています。
一方で「サーバレスの制約 (10 秒 / bandwidth / cold start)」を最初から 設計に織り込んでおくことが重要です。バッチは外に逃す、画像は R2 に逃す、 env は必ずスコープ分ける、Rollback パスは 3 通り用意する。この基本を 踏めば、Vercel + Next.js は「1 人でも本番運用できる Platform」として 非常に強力です。
この記事を書いた背景
ClearNets は 2025 年から Vercel + Next.js の組合せで全プロダクトを 運用しており、本記事の数字と事例はすべて 2026 年 8 月時点の実測 / 実際のインシデントログに基づきます。Vercel の料金体系や機能は 頻繁に更新されるため、最新情報は Vercel 公式 (vercel.com/pricing) を参照ください。