「Vercel はフロントエンドを置く場所で、バックエンドは別のサーバーが要るんでしょう?」——これは2026年には明確な誤解です。Vercel は Express・Hono・NestJS(Node.js)や FastAPI(Python)といったバックエンドフレームワークを、ほぼゼロ設定でそのまま動かすフルコンピュート基盤です。
この記事は Node.js ランタイムの公式仕様に忠実に、Vercel でバックエンドを本番運用する方法をまとめます。全体像は Vercel 本番運用ガイド、関数の詳細は Functions・Fluid Compute ガイド を参照してください。
3つのデプロイ形
Vercel でバックエンドを動かす形は3つあります。
| 形 | 書き方 | 向く場面 |
|---|---|---|
| Node.js サーバー検出 | server.ts で server.listen() | 既存の Express/Hono/Fastify アプリ「丸ごと」 |
| fetch Web Handler | api/*.ts で export default { fetch } | 軽量・Web 標準・関数単位 |
| HTTP メソッド別 export | api/*.ts で export function GET/POST | REST エンドポイント単位 |
① Node.js サーバーを丸ごと載せる
Vercel は、プロジェクトルートか src/ の server.{js,cjs,mjs,ts,cts,mts} を検出し、server.listen() の呼び出しを手がかりにHTTP サーバーを関数化します。listen() に渡すポートはローカル実行用で、本番では内部ポート経由でルーティングされます(公開ポートにはなりません)。
// server.ts — 標準の Node.js HTTP サーバー(Vercel が検出)
import { createServer } from "node:http";
const server = createServer((request, response) => {
const url = new URL(request.url ?? "/", `http://${request.headers.host}`);
if (request.method === "GET" && url.pathname === "/health") {
response.writeHead(200, { "Content-Type": "application/json" });
response.end(JSON.stringify({ status: "ok" }));
return;
}
response.writeHead(200, { "Content-Type": "text/plain" });
response.end("Hello from Node.js on Vercel");
});
// ローカル用ポート。Vercel はこの listen を検出してサーバーを捕捉する
server.listen(Number(process.env.PORT ?? 3000));
② Hono を載せる(fetch ハンドラと相性抜群)
Hono は Web 標準の fetch ハンドラなので、Vercel の Web Handler とそのまま噛み合います。
// api/index.ts — Hono を fetch Web Handler として
import { Hono } from "hono";
const app = new Hono();
app.get("/api/health", (c) => c.json({ status: "ok" }));
app.post("/api/echo", async (c) => c.json(await c.req.json()));
// Vercel は fetch エクスポートをそのまま関数として実行する
export default { fetch: app.fetch };
③ Express を載せる
Express は Node.js で最も使われるフレームワークで、Vercel に専用ガイドがあります。基本は server.listen() でサーバー検出に乗せるか、サーバーレス用アダプタでハンドラ化します。
// server.ts — Express を Node.js サーバー検出に乗せる
import express from "express";
const app = express();
app.use(express.json());
app.get("/api/health", (_req, res) => res.json({ status: "ok" }));
app.listen(Number(process.env.PORT ?? 3000)); // Vercel が検出
④ NestJS
NestJS は Express/Fastify をアダプタに持つので、bootstrap() で listen() を呼ぶ標準構成がそのまま乗ります(重い初期化はコールドスタートに効くので注意)。
// server.ts
import { NestFactory } from "@nestjs/core";
import { AppModule } from "./app.module";
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(Number(process.env.PORT ?? 3000));
}
bootstrap();
⑤ FastAPI(Python)
Vercel は Python(3.13/3.14)も Fluid Compute で動かします。FastAPI を ASGI アプリとしてデプロイできます。
# api/index.py — FastAPI on Vercel(Python ランタイム)
from fastapi import FastAPI
app = FastAPI()
@app.get("/api/health")
def health():
return {"status": "ok"}
FastAPI 本体の本番設計(非同期・Pydantic・DI)は FastAPI 本番ガイド を参照。
最大の注意:Fluid Compute のグローバル状態
どのフレームワークでも、Vercel(Fluid Compute)では1つのインスタンスが複数リクエストを並行処理します。だから、モジュールスコープにリクエスト固有の状態を置くと漏洩します。
// ❌ 危険:Express の app レベルやモジュールスコープに「現在のユーザー」を持つ
let currentUser; // 全リクエストで共有される
// ✅ 安全:リクエスト固有はハンドラ内のローカルに閉じる
app.get("/me", (req, res) => {
const user = authenticate(req); // ローカル
res.json(user);
});
// ✅ グローバルに置いてよいのは「リクエスト非依存」のものだけ
const pool = createPool(process.env.DATABASE_URL!); // 接続プール
これは「サーバーで1プロセス1リクエスト」に慣れた人ほど見落とします。詳細は Functions・Fluid Compute ガイド の「共有グローバル状態」を参照。
バックエンド設計の前提(制限)
Vercel でバックエンドを設計するときの前提(Functions 制限):
- タイムアウト:既定300秒、Pro/Ent 最大800秒。長時間処理は Workflows/キューへ。
- ボディ:リクエスト/レスポンス本文 4.5MB。大きなアップロードは Blob の client upload。
- メモリ/CPU:Pro/Ent 最大 4GB/2vCPU。
- DB 接続:サーバーレスの並行性で枯渇しやすい → pooled 接続(接続プーリング)。
- 状態:ステートレスに。状態は外部(DB/Blob/Redis)へ。
- コスト:Active CPU 課金(I/O 待ち非課金)。I/O 主体の API は効率的。
フロントとバックエンドの同居:Services
Next.js のフロントと Node.js サーバーを同一プロジェクトで併存させたい場合は、Services を使います。フロントは Next.js、API は別の Node.js サーバーとして、1つのプロジェクト内で動かせます。BFF パターン(フロント専用のバックエンド)をモノレポで組むのに向きます。
マイクロサービス的に分けるなら、フロント=Next.js プロジェクト、API=別プロジェクトに分離し、
rewritesでつなぐ構成も有効です(vercel.ts のrewrite)。
いつ「Vercel でバックエンド」が向くか
| 向く | 向きにくい |
|---|---|
| REST/GraphQL/BFF・Webhook 受け | 常駐 WebSocket サーバー(SSE か外部基盤へ) |
| I/O 主体(DB/外部API/AI) | 数分超の重い CPU バッチ(Workflows へ) |
| Next.js と同居の API | 巨大モノリス(250MB バンドル超) |
| スパイクするトラフィック(自動スケール) | VPC 内のみ・公開不可な専用DB(要 Secure Compute 等) |
向かないものは「分離」で解けます——長時間は Workflows、常駐は外部基盤、巨大は機能分割。
本番チェックリスト(バックエンド on Vercel)
- サーバー検出(
server.listen())か Web Handler か、形を選択 - グローバル状態にリクエスト固有データを置いていない
- DB は pooled 接続、状態は外部ストアへ(ステートレス)
- タイムアウト300秒・ボディ4.5MB を前提に設計、超える処理は分離
- 重い初期化を避けコールドスタートを抑える
- フロント同居は Services、分離は
rewrites - Active CPU 課金前提でコスト設計、Observability で監視
まとめ
Vercel は「フロントを置く場所」ではなく、Express・Hono・NestJS・FastAPI をゼロ設定で動かすバックエンド基盤でもあります。
- 3つの形(サーバー検出 / fetch Handler / メソッド別)から選ぶ
- Fluid のグローバル状態に注意(リクエスト固有はローカルに)
- ステートレス・pooled 接続・4.5MB・300秒を前提に設計
- 長時間/常駐/巨大は分離で解く
- フロント同居は Services
Next.js フロント+Vercel バックエンドの一気通貫構成(BFF・API・Webhook)を、設計から本番運用まで承ります。
本記事は Node.js ランタイム / Functions 制限 公式ドキュメント(2026年6月時点)に基づきます。仕様は更新されるため、本番採用時は公式で最新値を確認してください。