# Vercel ストレージ実装ガイド：Blob・Edge Config・Marketplace(Neon/Upstash) を用途で正しく選ぶ

> Vercel公式に忠実なストレージ選定・実装ガイド。Vercel Blob（public/private・@vercel/blobのput/del/list・client/serverアップロード・条件付き書き込みifMatch・multipart・S3バックエンド11 nines）、Edge Config（P99 15ms未満のグローバル読み取り・機能フラグ/リダイレクト/IPブロック）、Marketplace（Neon Postgres・Upstash Redis、Vercel Postgres/KVは提供終了）を実コードで解説します。

- 公開日: 2026-06-28
- 著者: 友田 陽大
- タグ: Vercel, ストレージ, Next.js, TypeScript, コスト最適化, アーキテクチャ設計, PostgreSQL
- URL: https://tomodahinata.com/blog/vercel-storage-blob-edge-config-marketplace-guide
- カテゴリ: Vercel 本番運用
- 総合ガイド: https://tomodahinata.com/blog/vercel-production-platform-guide

## 要点

- Vercel Postgres / Vercel KV は提供終了。いまは用途で選ぶ——オブジェクトはVercel Blob、超低遅延の読み取りはEdge Config、リレーショナルDBはMarketplaceのNeon（Postgres）、KV/Redisは同じくUpstash
- Vercel Blobはpublic/private（作成後変更不可）。@vercel/blobのput/del/list/head/copyで操作。大きなファイルやユーザーアップロードはclient uploadでデータ転送課金を避け、サーバーを経由しない。S3バックエンドで11 nines耐久性・4 nines可用性、20リージョン
- Blobは衝突防止にaddRandomSuffix、上書きにallowOverwrite、楽観的並行制御にifMatch（ETag一致時のみ成功、BlobPreconditionFailedError）。100MB超はmultipart推奨。基本はイミュータブル（新pathnameで作る）が安全
- Edge ConfigはP99 15ms未満（多くは1ms未満）のグローバル読み取り専用ストア。機能フラグ・緊急リダイレクト・IPブロックなど『読み高頻度・書き低頻度』に最適。読み取りはread token、書き込みはAPI tokenで保護
- Marketplace統合はvercel integrationで接続し、環境変数を自動注入・請求も統一。サーバーレスのPostgresは接続枯渇に注意し、接続プーリング（Neonのpooled接続/PgBouncer相当）を使う

---

「Vercel でデータをどこに置くか」は、2026年に大きく変わりました。かつての **Vercel Postgres / Vercel KV は提供終了**し、いまは**用途ごとに最適なストレージを選ぶ**設計になっています。選定を誤ると、コスト・レイテンシ・接続枯渇で痛い目を見ます。この記事は [Vercel Blob](https://vercel.com/docs/vercel-blob) と [Edge Config](https://vercel.com/docs/edge-config)、[Marketplace](https://vercel.com/docs/integrations) の公式仕様に忠実に、実コードで選び方と使い方をまとめます。

全体像は [Vercel 本番運用ガイド](/blog/vercel-production-platform-guide) を参照してください。

---

## 用途で選ぶ：4つの選択肢

| 置きたいもの | 選択肢 | 一言で |
|---|---|---|
| **オブジェクト**（画像・動画・PDF・大容量ファイル） | **Vercel Blob** | S3 バックエンドのオブジェクトストレージ。CDN 配信 |
| **超低遅延で読む小さなデータ**（フラグ・リダイレクト・IPリスト） | **Edge Config** | P99 15ms 未満のグローバル読み取り |
| **リレーショナルDB** | **Marketplace: Neon (Postgres)** | サーバーレス Postgres。環境変数自動注入 |
| **KV / キャッシュ / レート制限** | **Marketplace: Upstash (Redis)** | サーバーレス Redis |

判断のショートカット：

- ユーザーがアップロードするファイル → **Blob（client upload）**
- 「メンテモード ON/OFF」のような**読み高頻度・書き低頻度**の設定 → **Edge Config**
- トランザクション・リレーション・集計が要る本体データ → **Neon (Postgres)**
- セッション・キャッシュ・分散レート制限 → **Upstash (Redis)**

---

## Vercel Blob：オブジェクトストレージ

### public と private（作成後は変更不可）

Blob ストアは**作成時に public か private を選び、後から変更できません**。アクセスモードで配信経路が変わります（[Blob docs](https://vercel.com/docs/vercel-blob)）。

| | Private | Public |
|---|---|---|
| 書き込み | 認証必須 | 認証必須 |
| 読み取り | 認証必須（トークン要） | URL を知る誰でも |
| 配信 | **関数経由**（`get()`） | 直接 Blob URL |
| 向き | 機密文書・ユーザーコンテンツ | 大容量メディア・公開アセット |

> **選択を誤らない**：請求書 PDF・本人確認書類のような機密は **private** 一択。アバターや公開画像は **public**。作成後に変えられないので、用途ごとにストアを分けます。

### 基本操作（@vercel/blob）

```ts
import { put, del, list, head, copy } from "@vercel/blob";

// アップロード（put）
const blob = await put(`invoices/${id}.pdf`, pdfBuffer, {
  access: "private",        // 'public' も
  addRandomSuffix: true,    // 'invoices/abc-<random>.pdf' 衝突防止
  contentType: "application/pdf",
});

// メタデータ取得（head）— ETag も取れる
const meta = await head(blob.url);

// 一覧（list）— prefix でフォルダ的に絞る
const { blobs } = await list({ prefix: "invoices/", limit: 1000 });

// 削除（del）— 課金対象外（無料）
await del(blob.url);
```

### ユーザーアップロードは client upload で

ユーザーがアップロードするファイルを**いったんサーバー（関数）で受けて Blob へ**転送すると、関数のデータ転送課金がかかり、4.5MB のリクエスト本文制限にも当たります。**client upload** なら、ブラウザから**直接 Blob へ**送れ、データ転送課金もかかりません。

```ts
// サーバー：アップロード用トークンを発行（認可をここで行う）
// app/api/upload/route.ts
import { handleUpload, type HandleUploadBody } from "@vercel/blob/client";

export async function POST(request: Request): Promise<Response> {
  const body = (await request.json()) as HandleUploadBody;
  const json = await handleUpload({
    body,
    request,
    onBeforeGenerateToken: async (pathname) => {
      // ★ ここで認証・拡張子・サイズ制限などの認可を行う
      await assertAuthenticated(request);
      return {
        allowedContentTypes: ["image/jpeg", "image/png", "application/pdf"],
        addRandomSuffix: true,
      };
    },
    onUploadCompleted: async ({ blob }) => {
      // アップロード完了後の後処理（DBへURL保存など）
      await saveBlobReference(blob.url);
    },
  });
  return Response.json(json);
}
```

```tsx
// クライアント：ブラウザから直接 Blob へ（サーバーを経由しない）
"use client";
import { upload } from "@vercel/blob/client";

async function onFile(file: File) {
  const blob = await upload(file.name, file, {
    access: "public",
    handleUploadUrl: "/api/upload", // ↑のトークン発行エンドポイント
  });
  return blob.url;
}
```

100MB 超のファイルは **multipart upload** が推奨（`put`/`upload` が分割・並列・再開を自動処理。ネットワーク断でも該当パートだけ再送）。

### 並行更新を安全に：条件付き書き込み（ifMatch）

同じ Blob を複数プロセスが更新しうるとき（共有設定ファイル等）は、**楽観的並行制御**を使います。`head()`/`get()` で得た ETag を `ifMatch` に渡すと、**その後変更されていないときだけ**成功します。

```ts
import { head, put, BlobPreconditionFailedError } from "@vercel/blob";

const meta = await head("config.json");
try {
  await put("config.json", JSON.stringify(next), {
    access: "private",
    allowOverwrite: true,
    ifMatch: meta.etag, // 他プロセスが更新していたら失敗
  });
} catch (e) {
  if (e instanceof BlobPreconditionFailedError) {
    // 競合：再読込してリトライ or 衝突処理
  }
  throw e;
}
```

### キャッシュとイミュータブル運用

Blob は CDN に**既定1ヶ月**キャッシュされます（`cacheControlMaxAge` で変更可）。更新・削除の反映は**最大60秒**かかり、ブラウザキャッシュは別途。だから公式の推奨は**「Blob はイミュータブルに扱う」**——更新ではなく**新しい pathname で作る**（`addRandomSuffix` か timestamp/UUID）。どうしても同一URLで更新したいデータ（5分ごとのランキングJSON 等）だけ、短い `cacheControlMaxAge` で上書きします。

耐久性は S3 バックエンドで **99.999999999%（11 nines）**、可用性 **99.99%（4 nines）**。安心して本番のファイル基盤に使えます。

---

## Edge Config：超低遅延のグローバル読み取り

### 何が嬉しいか

Edge Config は「**読み取りが速く・書き込みが稀**」なデータのためのグローバルストアです。P99 **15ms 未満**（多くは **1ms 未満**）で、外部DBを叩かずにユーザー最寄りで読めます（[Edge Config docs](https://vercel.com/docs/edge-config)）。

代表的な用途：

- **機能フラグ / A-B テスト**：再デプロイなしで ON/OFF
- **緊急リダイレクト / メンテモード**：障害時、コードを触らず即リダイレクト
- **IP ブロックリスト**：悪性 IP をアップストリームを呼ばずに弾く

### 読む（SDK）

```ts
// Middleware や関数で（@vercel/edge-config）
import { get, getAll, has } from "@vercel/edge-config";

// 機能フラグ
const newCheckout = await get<boolean>("feature_new_checkout");

// メンテモード（Routing Middleware で全リクエストに対し超低遅延で判定）
export async function middleware(request: Request) {
  if (await get<boolean>("maintenance_mode")) {
    return Response.redirect(new URL("/maintenance", request.url));
  }
}
```

### 書く・守る

- **読み取り**は read access token、**書き込み**は API token で保護（**既定でセキュア**）。
- 書き込みは**リクエストパスの外**（ダッシュボード or REST API）で行う設計。つまり「アプリの応答中に書く」ものではありません。
- Vercel の読み取り最適化が効くのは **Edge / Node.js ランタイム**（他は要申請）。

> **DB の代わりではない**：Edge Config は「小さく・更新が稀な設定」のためのもの。ユーザーデータや頻繁に書くデータは Neon/Upstash へ。環境変数との違いは「**再デプロイ不要で更新でき、ダウンタイムリスクがない**」点です。

---

## Marketplace：Neon・Upstash を統合する

リレーショナルDBやRedisは、**Vercel Marketplace** から統合します。`vercel integration` で接続すると、**接続文字列などの環境変数が自動注入**され、**請求も Vercel に統一**されます。

```bash
# Marketplace 統合の接続（例）
vercel integration add neon       # サーバーレス Postgres
vercel integration add upstash    # サーバーレス Redis
vercel env pull .env.local        # 注入された接続情報をローカルへ
```

### サーバーレスでの接続枯渇に注意

Postgres は「1接続＝1プロセス」が重く、**Fluid Compute の並行性**下では接続が枯渇しがちです。対策は**接続プーリング**——Neon の **pooled 接続文字列**（内部的に PgBouncer 相当）を使い、サーバーレスからは pooled エンドポイントへ繋ぎます。

```ts
// Neon：pooled 接続を使う（サーバーレスでは必須級）
import { neon } from "@neondatabase/serverless";
const sql = neon(process.env.DATABASE_URL!); // pooled エンドポイント

export async function GET() {
  const rows = await sql`SELECT id, title FROM posts ORDER BY created_at DESC LIMIT 20`;
  return Response.json(rows);
}
```

接続プーリングの設計原則（なぜサーバーレスで必須か、トランザクションモードの制約）は [PostgreSQL 接続プーリング・PgBouncer ガイド](/blog/postgresql-connection-pooling-pgbouncer-serverless-guide) に詳しくまとめています。型安全な ORM を被せるなら [Drizzle ORM](/blog/drizzle-orm-typescript-type-safe-database-production-guide) や [Prisma v7](/blog/prisma-orm-production-guide-type-safe-database-v7-driver-adapters) を、Redis での分散レート制限は [サーバーレスレート制限](/blog/nextjs-serverless-rate-limiting-vercel-guide) を参照してください。

---

## 本番チェックリスト（ストレージ）

- [ ] データの性質（オブジェクト/設定/リレーショナル/KV）で**置き場所を選択**
- [ ] Blob は public/private を**用途で確定**（作成後変更不可）
- [ ] ユーザーアップロードは **client upload**（転送課金・4.5MB制限を回避）、トークン発行で**認可**
- [ ] Blob は**イミュータブル運用**（`addRandomSuffix`）、並行更新は `ifMatch`
- [ ] 機密ファイルは **private**＋関数経由配信
- [ ] 機能フラグ・メンテモードは **Edge Config**（再デプロイ不要）
- [ ] Postgres は **pooled 接続**で接続枯渇を防止
- [ ] Marketplace 統合の**環境変数は自動注入**、秘密はコードに書かない

---

## まとめ

2026年の Vercel ストレージは「1つの DB に全部」ではなく、**用途ごとの最適解を組み合わせる**設計です。

1. **オブジェクトは Blob**（client upload・イミュータブル・private/public を正しく）
2. **読み高頻度の設定は Edge Config**（超低遅延・再デプロイ不要）
3. **リレーショナルは Neon**、**KV/Redis は Upstash**（Marketplace 統合）
4. サーバーレスでは **接続プーリング**で枯渇を防ぐ
5. 秘密は環境変数、Blob のアップロードは**認可をトークン発行で**

次は、これらを**安く**運用する [コスト・Active CPU 最適化ガイド](/blog/vercel-cost-active-cpu-pricing-optimization-guide) へ。

> 本記事は [Vercel Blob](https://vercel.com/docs/vercel-blob) / [Edge Config](https://vercel.com/docs/edge-config) / [Marketplace](https://vercel.com/docs/integrations) 公式ドキュメント（2026年6月時点）に基づきます。仕様・上限・料金は更新されるため、本番採用時は公式で最新値を確認してください。
