# Vercel でバックエンドを動かす：Express・Hono・FastAPI・NestJS をゼロ設定で本番運用する

> Vercelはフロント専用ではなくフルコンピュート基盤。Express・Hono・NestJS（Node.js 24）やFastAPI（Python）をゼロ設定で動かす方法を公式準拠で解説。server.listenによるNodeサーバー検出、fetch Web Handler、apiディレクトリ、Fluid Computeでの並行性とグローバル状態の注意、フロントとの同居（Services）までを実コードで。

- 公開日: 2026-06-28
- 著者: 友田 陽大
- タグ: Vercel, Fluid Compute, Python, TypeScript, サーバーレス, アーキテクチャ設計, 可観測性
- URL: https://tomodahinata.com/blog/vercel-backend-express-fastapi-nestjs-hono-fullstack-guide
- カテゴリ: Vercel 本番運用
- 総合ガイド: https://tomodahinata.com/blog/vercel-production-platform-guide

## 要点

- Vercelはフロント専用ホストではなくフルコンピュート基盤。Express・Hono・NestJS（Node.js）やFastAPI（Python）といったバックエンドフレームワークをゼロ設定で動かせる。Fluid Computeの上で通常のNode.js/Pythonが動く
- Node.jsサーバーは『server.{js,ts}をルートかsrc/に置きserver.listen()を呼ぶ』だけでVercelが検出し関数化する。listenのポートはローカル用で、本番では内部ポート経由でルーティングされる
- 個別の関数はfetch Web Handler（export default { fetch }）かHTTPメソッド別export（GET/POST）で書ける。Expressは専用ガイドあり、Honoは標準のfetchハンドラと相性が良い
- 最大の注意はFluid Computeのグローバル状態共有。1インスタンスが複数リクエストを並行処理するため、リクエスト固有データをモジュールスコープに置くと漏洩する。共有はDB接続プールなどリクエスト非依存のものだけ
- フロント（Next.js）とNode.jsサーバーを同一プロジェクトで併存させるならServicesを使う。重い/長時間処理はWorkflows・キューへ分離し、4.5MBのボディ制限と300秒のタイムアウトを前提に設計する

---

「Vercel はフロントエンドを置く場所で、バックエンドは別のサーバーが要るんでしょう？」——これは2026年には**明確な誤解**です。Vercel は **Express・Hono・NestJS（Node.js）や FastAPI（Python）といったバックエンドフレームワークを、ほぼゼロ設定でそのまま動かすフルコンピュート基盤**です。

この記事は [Node.js ランタイム](https://vercel.com/docs/functions/runtimes/node-js)の公式仕様に忠実に、Vercel でバックエンドを本番運用する方法をまとめます。全体像は [Vercel 本番運用ガイド](/blog/vercel-production-platform-guide)、関数の詳細は [Functions・Fluid Compute ガイド](/blog/vercel-functions-fluid-compute-streaming-cron-guide) を参照してください。

---

## 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()` に渡すポートは**ローカル実行用**で、本番では内部ポート経由でルーティングされます（公開ポートにはなりません）。

```ts
// 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 とそのまま噛み合います。

```ts
// 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 に[専用ガイド](https://vercel.com/kb/guide/using-express-with-vercel)があります。基本は `server.listen()` でサーバー検出に乗せるか、サーバーレス用アダプタでハンドラ化します。

```ts
// 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()` を呼ぶ標準構成がそのまま乗ります（重い初期化はコールドスタートに効くので注意）。

```ts
// 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 アプリとしてデプロイできます。

```python
# 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 本番ガイド](/blog/fastapi-production-async-pydantic-observability-guide) を参照。

---

## 最大の注意：Fluid Compute のグローバル状態

どのフレームワークでも、Vercel（Fluid Compute）では**1つのインスタンスが複数リクエストを並行処理**します。だから、**モジュールスコープにリクエスト固有の状態を置くと漏洩**します。

```ts
// ❌ 危険：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 ガイド](/blog/vercel-functions-fluid-compute-streaming-cron-guide) の「共有グローバル状態」を参照。

---

## バックエンド設計の前提（制限）

Vercel でバックエンドを設計するときの前提（[Functions 制限](https://vercel.com/docs/functions/limitations)）：

- **タイムアウト**：既定300秒、Pro/Ent 最大800秒。長時間処理は Workflows/キューへ。
- **ボディ**：リクエスト/レスポンス本文 **4.5MB**。大きなアップロードは [Blob の client upload](/blog/vercel-storage-blob-edge-config-marketplace-guide)。
- **メモリ/CPU**：Pro/Ent 最大 4GB/2vCPU。
- **DB 接続**：サーバーレスの並行性で枯渇しやすい → **pooled 接続**（[接続プーリング](/blog/postgresql-connection-pooling-pgbouncer-serverless-guide)）。
- **状態**：ステートレスに。状態は外部（DB/Blob/Redis）へ。
- **コスト**：[Active CPU 課金](/blog/vercel-cost-active-cpu-pricing-optimization-guide)（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](/blog/vercel-deployments-cicd-rollback-rolling-releases-guide)）。

---

## いつ「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 をゼロ設定で動かすバックエンド基盤**でもあります。

1. **3つの形**（サーバー検出 / fetch Handler / メソッド別）から選ぶ
2. **Fluid のグローバル状態**に注意（リクエスト固有はローカルに）
3. **ステートレス・pooled 接続・4.5MB・300秒**を前提に設計
4. 長時間/常駐/巨大は**分離**で解く
5. フロント同居は **Services**

Next.js フロント＋Vercel バックエンドの一気通貫構成（BFF・API・Webhook）を、設計から本番運用まで承ります。

> 本記事は [Node.js ランタイム](https://vercel.com/docs/functions/runtimes/node-js) / [Functions 制限](https://vercel.com/docs/functions/limitations) 公式ドキュメント（2026年6月時点）に基づきます。仕様は更新されるため、本番採用時は公式で最新値を確認してください。
