mcpField
N
neon-vercel-postgres

neon-vercel-postgres

github.com/jezwebデータ・データベース1.1k363 回インストール3 週間前に更新
リポジトリ

neon-vercel-postgres について

サーバーレスやエッジ環境にアプリをデプロイする開発者向けに、Neon または Vercel Postgres の利用方法を解説するスキルです。設定、安全なクエリ、接続プーリング、スキーマ管理、デプロイ時の注意点を扱います。

主な機能

  1. 01Neon と Vercel の設定ガイド
  2. 02サーバーレス接続プーリング
  3. 03SQL テンプレートタグによるクエリ
  4. 04Drizzle と Prisma のスキーマ運用
  5. 05トランザクションとデプロイの手順

活用シーン

  1. 01Cloudflare Workers から Postgres に接続
  2. 02Vercel で Next.js アプリを構築
  3. 03サーバーレス環境で接続枯渇を防止
  4. 04スキーマ作成とマイグレーション実行

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/jezweb/claude-skills --skill neon-vercel-postgres

インストール後、Claude Code で/neon-vercel-postgresを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

README.md
.claude-plugin/
plugin.json
assets/
drizzle-schema.ts
example-template.txt
references/
example-reference.md
scripts/
example-script.sh
test-connection.ts
templates/
drizzle-migrations-workflow.md
drizzle-queries.ts
drizzle-schema.ts
neon-basic-queries.ts
package.json

詳細

Neon & Vercel Serverless Postgres

ステータス:本番環境対応済み 最終更新日:2026-01-21 依存関係:なし 最新バージョン:@neondatabase/[email protected]、@vercel/[email protected]、[email protected]、[email protected]、[email protected]


クイックスタート(5 分)

1. プラットフォームを選択する

オプション A:Neon Direct(マルチクラウド、Cloudflare Workers、あらゆるサーバーレス環境)

npm install @neondatabase/serverless

オプション B:Vercel Postgres(Vercel 専用、Vercel で設定不要)

npm install @vercel/postgres

注:どちらも同じ Neon バックエンドを使用します。Vercel Postgres は、Vercel 固有の環境設定を備えた Neon です。

重要な理由:

  • Neon Direct では、マルチクラウドの柔軟性とブランチ API を利用できます
  • Vercel Postgres では、Vercel 上で設定不要で、自動的に環境変数が設定されます
  • どちらも HTTP ベース(TCP 不使用)で、サーバーレス/エッジ環境に最適です
2. 接続文字列を取得する

Neon Direct の場合:

# Sign up at https://neon.tech
# Create a project → Get connection string
# Format: postgresql://user:[email protected]/dbname?sslmode=require

Vercel Postgres の場合:

# In your Vercel project
vercel postgres create
vercel env pull .env.local  # Automatically creates POSTGRES_URL and other vars

重要:

  • サーバーレスではプール済み接続文字列(末尾が -pooler.region.aws.neon.tech のもの)を使用してください
  • プールされていない接続は、サーバーレス環境ではすぐに枯渇します
  • 必ず ?sslmode=require パラメーターを含めてください
3. データベースにクエリを実行する

Neon Direct(Cloudflare Workers、Vercel Edge、Node.js):

import { neon } from '@neondatabase/serverless';

const sql = neon(process.env.DATABASE_URL!);

// Simple query
const users = await sql`SELECT * FROM users WHERE id = ${userId}`;

// Transactions
const result = await sql.transaction([
  sql`INSERT INTO users (name) VALUES (${name})`,
  sql`SELECT * FROM users WHERE name = ${name}`
]);

Vercel Postgres(Next.js Server Actions、API Routes):

import { sql } from '@vercel/postgres';

// Simple query
const { rows } = await sql`SELECT * FROM users WHERE id = ${userId}`;

// Transactions
const client = await sql.connect();
try {
  await client.sql`BEGIN`;
  await client.sql`INSERT INTO users (name) VALUES (${name})`;
  await client.sql`COMMIT`;
} finally {
  client.release();
}

重要:

  • SQL インジェクションを自動的に防ぐには、テンプレートタグ構文(sql`...`)を使用してください
  • 文字列を連結しないでください:sql('SELECT * FROM users WHERE id = ' + id) ❌
  • テンプレートタグは値を自動的にエスケープし、SQL インジェクションを防ぎます

7 ステップのセットアップ手順

ステップ 1:パッケージをインストールする

デプロイ先のプラットフォームに応じて選択してください:

Neon Direct(Cloudflare Workers、マルチクラウド、Neon への直接アクセス):

npm install @neondatabase/serverless

Vercel Postgres(Vercel 専用、設定不要):

npm install @vercel/postgres

ORM を使用する場合:

# Drizzle ORM (recommended for edge compatibility)
npm install [email protected] @neondatabase/[email protected]
npm install -D [email protected]

# Prisma (Node.js only)
npm install prisma @prisma/client @prisma/adapter-neon @neondatabase/serverless

ポイント:

  • どちらのパッケージも HTTP/WebSocket を使用します(TCP は不要)
  • エッジに対応しています(Cloudflare Workers、Vercel Edge Runtime で動作します)
  • プール済み接続文字列を使用すると、接続プーリングが組み込まれます
  • 別途、接続プールライブラリを用意する必要はありません

ステップ 2:Neon データベースを作成する

オプション A:Neon ダッシュボード

  1. https://neon.tech でサインアップします
  2. 新しいプロジェクトを作成します
  3. プール済み接続文字列をコピーします(重要です!)
  4. 形式:postgresql://user:[email protected]/db?sslmode=require

オプション B:Vercel ダッシュボード

  1. Vercel プロジェクト → Storage → Create Database → Postgres に移動します
  2. Vercel が自動的に Neon データベースを作成します
  3. vercel env pull を実行して、ローカルで環境変数を取得します

オプション C:Neon CLI([email protected])

# Install CLI
npm install -g [email protected]

# Authenticate
neonctl auth

# Create project and get connection string
neonctl projects create --name my-app
neonctl connection-string main

重要:

  • 必ずプール済み接続文字列(末尾が -pooler.region.aws.neon.tech のもの)を使用してください
  • プールされていない接続は直接接続用です(サーバーレスでは使用しません)
  • 接続文字列に ?sslmode=require を含めてください

ステップ 3:環境変数を設定する

Neon Direct の場合:

# .env or .env.local
DATABASE_URL="postgresql://user:[email protected]/neondb?sslmode=require"

Vercel Postgres の場合:

# Automatically created by `vercel env pull`
POSTGRES_URL="..."               # Pooled connection (use this for queries)
POSTGRES_PRISMA_URL="..."        # For Prisma migrations
POSTGRES_URL_NON_POOLING="..."   # Direct connection (avoid in serverless)
POSTGRES_USER="..."
POSTGRES_HOST="..."
POSTGRES_PASSWORD="..."
POSTGRES_DATABASE="..."

Cloudflare Workers の場合(wrangler.jsonc):

{
  "vars": {
    "DATABASE_URL": "postgresql://user:[email protected]/neondb?sslmode=require"
  }
}

ポイント:

  • クエリには POSTGRES_URL(プール済み)を使用してください
  • Prisma のマイグレーションには POSTGRES_PRISMA_URL を使用してください
  • サーバーレス関数では POSTGRES_URL_NON_POOLING を使用しないでください
  • シークレットは安全に保管してください(Vercel env、Cloudflare secrets など)

ステップ 4:データベーススキーマを作成する

オプション A:生の SQL

// scripts/migrate.ts
import { neon } from '@neondatabase/serverless';

const sql = neon(process.env.DATABASE_URL!);

await sql`
  CREATE TABLE IF NOT EXISTS users (
    id SERIAL PRIMARY KEY,
    name TEXT NOT NULL,
    email TEXT UNIQUE NOT NULL,
    created_at TIMESTAMP DEFAULT NOW()
  )
`;

オプション B:Drizzle ORM(推奨)

// db/schema.ts
import { pgTable, serial, text, timestamp } from 'drizzle-orm/pg-core';

export const users = pgTable('users', {
  id: serial('id').primaryKey(),
  name: text('name').notNull(),
  email: text('email').notNull().unique(),
  createdAt: timestamp('created_at').defaultNow()
});
// db/index.ts
import { drizzle } from 'drizzle-orm/neon-http';
import { neon } from '@neondatabase/serverless';
import * as schema from './schema';

const sql = neon(process.env.DATABASE_URL!);
export const db = drizzle(sql, { schema });
# Run migrations
npx drizzle-kit generate
npx drizzle-kit migrate

オプション C:Prisma

// prisma/schema.prisma
generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("POSTGRES_PRISMA_URL")
}

model User {
  id        Int      @id @default(autoincrement())
  name      String
  email     String   @unique
  createdAt DateTime @default(now()) @map("created_at")

  @@map("users")
}
npx prisma migrate dev --name init

重要:

  • エッジ対応の ORM には Drizzle を使用してください(Cloudflare Workers で動作します)
  • Prisma には Node.js ランタイムが必要です(Cloudflare Workers では動作しません)
  • マイグレーションはエッジ関数ではなく、Node.js 環境から実行してください

ステップ 5:クエリパターン

重要 — テンプレートタグ構文が必須です:

// ✅ Correct: Template tag syntax (prevents SQL injection)
const users = await sql`SELECT * FROM users WHERE email = ${email}`;

// ❌ Wrong: String concatenation (SQL injection risk)
const users = await sql('SELECT * FROM users WHERE email = ' + email);

Neon トランザクション API(独自の機能):

// Automatic transaction (array of queries)
const results = await sql.transaction([
  sql`INSERT INTO users (name) VALUES (${name})`,
  sql`UPDATE accounts SET balance = balance - ${amount} WHERE id = ${accountId}`
]);

// Manual transaction with callback (for complex logic)
const result = await sql.transaction(async (sql) => {
  const [user] = await sql`INSERT INTO users (name) VALUES (${name}) RETURNING id`;
  await sql`INSERT INTO profiles (user_id) VALUES (${user.id})`;
  return user;
});

Vercel Postgres のトランザクション:

  • sql.connect() と手動の BEGIN/COMMIT/ROLLBACK を使用する必要があります
  • 接続リークを防ぐため、必ず finally ブロックで client.release() を呼び出してください

Drizzle のトランザクション:

await db.transaction(async (tx) => {
  await tx.insert(users).values({ name, email });
  await tx.insert(profiles).values({ userId: user.id });
});

ステップ 6:接続プーリングの処理

接続文字列の形式:

Pooled (serverless):     postgresql://user:[email protected]/db
Non-pooled (direct):     postgresql://user:[email protected]/db

使い分け:

  • プール済み(-pooler.):サーバーレス関数、エッジ関数、高い同時実行性が求められる場合
  • プールなし:長時間稼働するサーバー、マイグレーション、管理タスク、接続数の制限が問題にならない場合

自動プーリング(Neon/Vercel):

// Both packages handle pooling automatically when using pooled connection string
import { neon } from '@neondatabase/serverless';
const sql = neon(process.env.DATABASE_URL!); // Pooling is automatic

接続数の制限:

  • Neon Free Tier:同時接続数は 100
  • プール済み接続:リクエスト間で接続を共有します
  • プールなし:リクエストごとに新しい接続を取得します(すぐに上限に達します)

重要:

  • サーバーレス環境では、必ずプール済みの接続文字列を使用してください
  • プールなしの接続では、「connection pool exhausted」エラーが発生します
  • Neon ダッシュボードで接続の使用状況を監視してください

ステップ 7:デプロイとテスト

Cloudflare Workers:

// src/index.ts
import { neon } from '@neondatabase/serverless';

export default {
  async fetch(request: Request, env: Env) {
    const sql = neon(env.DATABASE_URL);
    const users = await sql`SELECT * FROM users`;
    return Response.json(users);
  }
};
# Deploy
npx wrangler deploy

Vercel(Next.js API Route):

// app/api/users/route.ts
import { sql } from '@vercel/postgres';

export async function GET() {
  const { rows } = await sql`SELECT * FROM users`;
  return Response.json(rows);
}
# Deploy
vercel deploy --prod

テストクエリ:

# Local test
curl http://localhost:8787/api/users

# Production test
curl https://your-app.workers.dev/api/users

重要なポイント:

  • デプロイ前にローカルでテストしてください
  • Neon ダッシュボードでクエリのパフォーマンスを監視してください
  • 接続プールの上限に達した場合のアラートを設定してください
  • デバッグには Neon のクエリ履歴を使用してください

重要なルール(Neon/Vercel 固有)

✅ 必ず行うこと:

  • サーバーレスでは、プール済み接続文字列(ホスト名に -pooler. を含む)を使用する
  • 接続文字列に ?sslmode=require を含める
  • SQL インジェクションを防ぐため、テンプレートタグ構文(sql`...`)を使用する
  • client.release() を finally ブロックで呼び出す(Vercel Postgres のトランザクションのみ)
  • Cloudflare Workers では Drizzle を使用する(Prisma には Node.js ランタイムが必要です)
  • クエリには POSTGRES_URL、Prisma のマイグレーションには POSTGRES_PRISMA_URL を使用する

❌ 絶対に行わないこと:

  • サーバーレスでプールなしの接続や POSTGRES_URL_NON_POOLING を使用する
  • SQL 文字列を連結する(テンプレートタグのみを使用する)
  • sslmode=require を省略する(接続に失敗します)
  • Cloudflare Workers で Prisma を使用する(V8 アイソレートは Prisma をサポートしていません)
  • エッジ関数からマイグレーションを実行する(Node.js 環境を使用してください)

既知の問題の防止

このスキルは、文書化されている 19 件の問題を防ぎます。

問題 #1:接続プールの上限超過

エラー:Error: connection pool exhausted または too many connections for role 出典:https://github.com/neondatabase/serverless/issues/12 発生原因:同時実行性の高いサーバーレス環境で、プールなしの接続文字列を使用している 防止策:必ずプール済み接続文字列を使用してください(ホスト名に -pooler. を含むもの)。接続文字列の形式を確認してください。

問題 #2:TCP 接続がサポートされていない

エラー:Error: TCP connections are not supported in this environment 出典:Cloudflare Workers のドキュメント 発生原因:従来の Postgres クライアントは TCP ソケットを使用しますが、エッジランタイムでは利用できない 防止策:pg や postgres.js パッケージの代わりに、@neondatabase/serverless(HTTP/WebSocket ベース)を使用してください。

問題 #3:文字列連結による SQL インジェクション

エラー:SQL インジェクション攻撃が成功する、または予期しないクエリ結果が返される 出典:OWASP SQL Injection Guide 発生原因:ユーザー入力を SQL 文字列に連結している:sql('SELECT * FROM users WHERE id = ' + id) 防止策:必ずテンプレートタグ構文を使用してください:sql`SELECT * FROM users WHERE id = ${id}`。テンプレートタグは値を自動的にエスケープします。

問題 #4:SSL モードの指定漏れ

エラー:Error: connection requires SSL または FATAL: no pg_hba.conf entry 出典:https://neon.tech/docs/connect/connect-securely 発生原因:接続文字列に ?sslmode=require パラメーターがない 防止策:必ず接続文字列の末尾に ?sslmode=require を追加してください。

Issue #5:接続リーク(Vercel Postgres)

エラー:メモリ使用量が徐々に増加し、最終的にタイムアウトエラーが発生します 原因: https://github.com/vercel/storage/issues/45 発生理由:手動トランザクション後に client.release() を呼び出し忘れています 防止策:常に try/finally ブロックを使用し、finally ブロックで client.release() を呼び出してください。

Issue #6:環境変数の誤り(Vercel)

エラー:Error: Connection string is undefined または connect ECONNREFUSED 原因: https://vercel.com/docs/storage/vercel-postgres/using-an-orm 発生理由:POSTGRES_URL の代わりに DATABASE_URL を使用している、またはその逆です 防止策:クエリには POSTGRES_URL を、Prisma のマイグレーションには POSTGRES_PRISMA_URL を使用してください。

Issue #7:エッジ関数でのトランザクションタイムアウト

エラー:Error: Query timeout または Error: transaction timeout 原因: https://neon.tech/docs/introduction/limits 発生理由:実行時間の長いトランザクションがエッジ関数のタイムアウト(通常 30 秒)を超過します 防止策:トランザクションを短く保ち(<5s)、操作をバッチ処理するか、複雑なトランザクションをバックグラウンドワーカーに移してください。

Issue #8:Cloudflare Workers での Prisma

エラー:Error: PrismaClient is unable to be run in the browser またはモジュール解決エラー 原因: https://github.com/prisma/prisma/issues/18765 発生理由:Prisma にはファイルシステムにアクセスできる Node.js ランタイムが必要です 防止策:Cloudflare Workers では Drizzle ORM を使用してください。Prisma は Vercel Edge/Node.js ランタイムでのみ動作します。

Issue #9:ブランチ API の認証エラー

エラー:Neon API の呼び出し時に Error: Unauthorized 原因: https://neon.tech/docs/api/authentication 発生理由:NEON_API_KEY 環境変数がないか、無効です 防止策:Neon ダッシュボードの「Account Settings」→「API Keys」で API キーを作成し、環境変数として設定してください。

Issue #10:ブランチ削除後の古い接続

エラー:ブランチ削除後に Error: database "xyz" does not exist 原因: https://neon.tech/docs/guides/branching 発生理由:アプリケーションが削除済みブランチの接続文字列を引き続き使用しています 防止策:ブランチを切り替える際に DATABASE_URL を更新し、ブランチの変更後にアプリケーションを再起動してください。

Issue #11:コールドスタート/自動一時停止時のクエリタイムアウト

エラー:アイドル期間後の最初のリクエストで Error: Query timeout、または Connection terminated unexpectedly 原因: Neon ドキュメント - 自動一時停止 | GitHub Issue #168 | 2025 年 12 月の変更履歴 発生理由:Neon は非アクティブ状態が約 5 分続くとコンピュートを自動一時停止します(無料プラン)。これにより、約 1~2 秒の起動遅延や接続の切断が発生します 防止策:

  • コールドスタートを考慮し、クエリタイムアウトを 10 秒以上に設定する
  • 自動一時停止を透過的に処理する HTTP クライアント(neon())を使用する
  • Pool で接続切断エラーを処理する:
import { Pool } from '@neondatabase/serverless';

const pool = new Pool({ connectionString: process.env.DATABASE_URL });

// CRITICAL: Handle connection termination errors
pool.on('error', (err) => {
  console.error('Unexpected database error:', err);
  // Implement reconnection logic or alerting
});
  • 本番環境の設定:安定したパフォーマンスを得るため、自動一時停止を無効にする
    • Neon コンソールで、最小コンピュートユニット数を 0 より大きく設定する
    • または、コンピュートサイズを 16 CU 以上にする(スケールゼロが自動的に無効になります)
    • トレードオフ:アイドル時間分の料金が発生しますが、安定して 100 ミリ秒未満のクエリを実現できます
    • 自動一時停止を無効にしていても、最高のパフォーマンスを得るにはプール接続文字列を使用してください
Issue #12:Drizzle スキーマの不一致

エラー:Property 'x' does not exist on type 'User' などの TypeScript エラー 原因: https://orm.drizzle.team/docs/generate 発生理由:データベースのスキーマが変更されたものの、Drizzle の型が再生成されていません 防止策:スキーマの変更後に npx drizzle-kit generate を実行し、生成されたファイルをコミットしてください。

問題 #13:ブランチ間のマイグレーション競合

エラー:Error: relation "xyz" already exists またはマイグレーションバージョンの競合 参照元:https://neon.tech/docs/guides/branching#schema-migrations 発生する理由:異なるマイグレーション履歴を持つ複数のブランチがあるためです。 予防策:main でマイグレーションを実行した後にブランチを作成するか、マージ前にブランチのスキーマをリセットしてください。

問題 #14:PITR のタイムスタンプが範囲外

エラー:Error: timestamp is outside retention window 参照元:https://neon.tech/docs/introduction/point-in-time-restore 発生する理由:保持期間より古いタイムスタンプから復元しようとしているためです(無料プランでは 7 日間)。 予防策:ご利用のプランの保持期間を確認し、許可された期間内に復元してください。

問題 #15:Prisma に不適切なアダプターを使用

エラー:Error: Invalid connection string またはクエリのパフォーマンスが低下する 参照元:https://www.prisma.io/docs/orm/overview/databases/neon 発生する理由:サーバーレス環境で @prisma/adapter-neon を使用していないためです。 予防策:@prisma/adapter-neon と @neondatabase/serverless をインストールし、HTTP ベースの接続を使用するように Prisma を設定してください。

問題 #16:エッジランタイムでは poolQueryViaFetch が必須

エラー:WebSocket is not defined、または use cache を使用した Next.js 15 のプリレンダリング中にタイムアウトする 参照元:Neon Docs - Prisma Guide | GitHub Issue #181 発生する理由:Cloudflare Workers などのエッジランタイムでは、Pool クエリに WebSocket ではなく HTTP が必要です。Next.js 15 の use cache ディレクティブでは、poolQueryViaFetch を使用して Pool を利用するとタイムアウトすることがあります。 予防策:エッジ環境で Pool を使用する前に、neonConfig.poolQueryViaFetch = true を設定してください。

import { Pool, neonConfig } from '@neondatabase/serverless';

// Enable Pool queries over HTTP fetch (required for edge)
neonConfig.poolQueryViaFetch = true;

const pool = new Pool({ connectionString: env.DATABASE_URL });

export default {
  async fetch(request: Request, env: Env) {
    // Pool.query() now uses HTTP instead of WebSocket
    const result = await pool.query('SELECT * FROM users');
    return Response.json(result.rows);
  }
};

注意点 — Next.js 15 の use cache:use cache ディレクティブと poolQueryViaFetch = true の併用は避け、代わりに neon() HTTP クライアントを使用してください。

// ❌ Can timeout during prerender
import { Pool, neonConfig } from '@neondatabase/serverless';
neonConfig.poolQueryViaFetch = true;
const pool = new Pool({ connectionString: process.env.DATABASE_URL });

async function getData() {
  'use cache';
  return await pool.query('SELECT * FROM data');
}

// ✅ Works with prerender
import { neon } from '@neondatabase/serverless';
const sql = neon(process.env.DATABASE_URL!);

async function getData() {
  'use cache';
  return await sql`SELECT * FROM data`;
}
問題 #17:Node v20 で並列処理を行うとトランザクションコンテキストが失われる

エラー:Promise.all() を使用したトランザクションでの外部キー制約違反:insert or update on table violates foreign key constraint 参照元:Drizzle Issue #2200 発生する理由:Neon のサーバーレスドライバーと Drizzle ORM を使用する Node.js v20 以降では、トランザクション内で Promise.all() を使用してデータベース操作を並列実行すると、トランザクションコンテキストが失われます。順次実行する操作は正しく動作します。これは、Node v20 における Neon ドライバーのセッション処理に固有の、トランザクションコンテキスト管理の問題です。 予防策:順次実行するか、Node.js 環境では postgres-js ドライバー(エッジ非対応)に切り替えてください。

// ❌ FAILS in Node v20 with Neon driver
await db.transaction(async (tx) => {
  const [user] = await tx.insert(users).values({ name: 'Alice' }).returning();

  // Parallel inserts lose transaction context
  await Promise.all([
    tx.insert(userSettings).values({ userId: user.id, theme: 'dark' }),
    tx.insert(userSettings).values({ userId: user.id, locale: 'en' })
  ]);
  // Error: Foreign key constraint violation (user.id not visible)
});

// ✅ WORKS - Sequential execution
await db.transaction(async (tx) => {
  const [user] = await tx.insert(users).values({ name: 'Alice' }).returning();

  await tx.insert(userSettings).values({ userId: user.id, theme: 'dark' });
  await tx.insert(userSettings).values({ userId: user.id, locale: 'en' });
});

// ✅ ALTERNATIVE - Use postgres-js driver for Node.js (not edge-compatible)
import { drizzle } from 'drizzle-orm/postgres-js';
import postgres from 'postgres';
const client = postgres(connectionString);
const db = drizzle(client);
// Promise.all() works correctly with this driver

影響を受ける設定:

  • Node.js:v20.12.2+
  • @neondatabase/serverless:v0.9.0+(v1.0.x まで確認済み)
  • drizzle-orm:v0.30.8+
  • パターン:トランザクション内の挿入を Promise.all() で並列実行
問題 #18:サンドボックス化されたランタイムでの process.env へのアクセス

エラー:ReferenceError: process is not defined 参照元:GitHub Issue #179 発生する理由:Neon のサーバーレスドライバーはトップレベルで process.env.* に無条件にアクセスします。そのため、process.env が提供されない Slack の Deno ランタイムなどのサンドボックス化されたランタイムでエラーが発生します。 影響を受ける環境:Slack Deno ランタイム、Node.js の process グローバルを持たないサンドボックス化された JavaScript 環境 予防策:現時点で回避策はありません。次のいずれかを行う必要があります。

  1. ランタイムで process.env をポリフィルする
  2. 別の Postgres ドライバーを使用する(Deno 互換の標準 pg)
  3. @neondatabase/serverless と process.env にアクセスする基盤の pg ライブラリの両方で、上流の修正を待つ

公式ステータス:修正時期が示されていない未解決の問題です。Neon ドライバーと基盤の pg ライブラリの両方に影響します。


v0.x から v1.0+ への移行

破壊的変更:v1.0.0 では、すべての SQL クエリでタグ付きテンプレート構文が必須です。 出典:Neon ブログ記事 | GitHub Issue #3678

変更前(v0.x):

const result = await sql("SELECT * FROM users WHERE id = $1", [userId]);

変更後(v1.0+):

// Option 1: Tagged template (recommended)
const result = await sql`SELECT * FROM users WHERE id = ${userId}`;

// Option 2: .query() method for parameterized queries
const result = await sql.query("SELECT * FROM users WHERE id = $1", [userId]);

// Option 3: .unsafe() for trusted raw SQL (dynamic identifiers)
const column = 'name';
const result = await sql`SELECT ${sql.unsafe(column)} FROM users`;

変更の理由:v1.0.0 リリースでは、SQL インジェクションの脆弱性を防ぐため、タグ付きテンプレート構文が必須になります。関数呼び出し構文 sql("...", [params]) は、実行時エラーをスローするようになりました。

エラーメッセージ:

This function can now be called only as a tagged-template function:
sql`SELECT ${value}`, not sql("SELECT $1", [value], options)

移行チェックリスト:

  • すべての sql("...", [params]) 呼び出しをタグ付きテンプレートに置き換える
  • better-auth を Drizzle と併用している場合は、drizzle-orm を v0.40.1+ にアップグレードする(非互換性を解消します)
  • 新しい構文ですべての動的クエリをテストする
  • SQL インジェクション防止のパターンを確認する(テンプレートタグが自動的にエスケープします)

better-auth ユーザー:better-auth v1.3.4+ と Neon v1.0.0+ を併用している場合は、互換性を解消するため、drizzle-orm を v0.40.1 以降にアップグレードしてください:

{
  "dependencies": {
    "@neondatabase/serverless": "^1.0.2",
    "better-auth": "^1.3.4",
    "drizzle-orm": "^0.40.1"
  }
}

代替の回避策:better-auth では Drizzle の代わりに Kysely を使用してください(drizzle-orm の更新なしで動作します):

import { Kysely } from 'kysely';
import { Pool } from '@neondatabase/serverless';

const db = new Kysely({
  dialect: new PostgresDialect({
    pool: new Pool({ connectionString: process.env.DATABASE_URL })
  })
});

パフォーマンスとプロトコルの選択

出典:Neon ブログ - HTTP と WebSocket の比較

HTTP と WebSocket のプロトコルでは、パフォーマンス特性が大きく異なります。選択によって、レイテンシ、スループット、および利用可能な Postgres の機能が変わります。

パフォーマンスのベンチマーク
  • HTTP の単一クエリ:初回レイテンシは約 37ms
  • WebSocket の初回接続:オーバーヘッドは約 15~20ms
  • WebSocket の2回目以降のクエリ:クエリごとに約 4~5ms
  • 損益分岐点:連続したクエリが2~3回(WebSocket の方が高速になります)
プロトコル選択マトリックス
ユースケース推奨理由
リクエストごとに単一クエリHTTP(neon())初回レイテンシが低い(約 37ms)
連続したクエリが2回以上WebSocket(Pool/Client)クエリごとのレイテンシが低い(約 5ms)
並列で実行する独立したクエリHTTP並列化に適している
インタラクティブトランザクションWebSocket(必須)トランザクションコンテキストに必要
エッジ関数(単発実行)HTTP接続のオーバーヘッドがない
長時間実行されるワーカーWebSocket接続コストを分散できる
コード例
// HTTP: Best for single queries
import { neon } from '@neondatabase/serverless';
const sql = neon(env.DATABASE_URL);
const users = await sql`SELECT * FROM users`; // ~37ms

// WebSocket: Best for multiple sequential queries
import { Pool } from '@neondatabase/serverless';
const pool = new Pool({ connectionString: env.DATABASE_URL });
const client = await pool.connect(); // ~15ms setup
try {
  const user = await client.query('SELECT * FROM users WHERE id = $1', [1]); // ~5ms
  const posts = await client.query('SELECT * FROM posts WHERE user_id = $1', [1]); // ~5ms
  const comments = await client.query('SELECT * FROM comments WHERE user_id = $1', [1]); // ~5ms
  // Total: ~30ms (vs ~111ms with HTTP)
} finally {
  client.release();
}
重要な制限事項

HTTP では次の機能をサポートしません:

  • インタラクティブトランザクション(BEGIN/COMMIT/ROLLBACK)
  • セッションレベルの機能(一時テーブル、プリペアドステートメント)
  • LISTEN/NOTIFY
  • COPY プロトコル

エッジ環境での WebSocket の制限事項:

  • リクエストをまたいで接続を維持できません
  • 1つのリクエストハンドラー内で接続、使用、切断を行う必要があります

設定ファイルのリファレンス

package.json(Neon Direct)
{
  "dependencies": {
    "@neondatabase/serverless": "^1.0.2"
  }
}
package.json(Vercel Postgres)
{
  "dependencies": {
    "@vercel/postgres": "^0.10.0"
  }
}
package.json(Drizzle ORM を使用)
{
  "dependencies": {
    "@neondatabase/serverless": "^1.0.2",
    "drizzle-orm": "^0.44.7"
  },
  "devDependencies": {
    "drizzle-kit": "^0.31.7"
  },
  "scripts": {
    "db:generate": "drizzle-kit generate",
    "db:migrate": "drizzle-kit migrate",
    "db:studio": "drizzle-kit studio"
  }
}
drizzle.config.ts
import { defineConfig } from 'drizzle-kit';

export default defineConfig({
  schema: './db/schema.ts',
  out: './db/migrations',
  dialect: 'postgresql',
  dbCredentials: {
    url: process.env.DATABASE_URL!
  }
});

これらの設定の理由:

  • @neondatabase/serverless はエッジに対応しています(HTTP/WebSocket ベース)
  • @vercel/postgres は Vercel 上で設定不要で利用できます
  • drizzle-orm はすべてのランタイム(Cloudflare Workers、Vercel Edge、Node.js)で動作します
  • drizzle-kit はマイグレーションとスキーマ生成を処理します

一般的なパターン

パターン1:Neon を使用する Cloudflare Worker
import { neon } from '@neondatabase/serverless';

interface Env { DATABASE_URL: string; }

export default {
  async fetch(request: Request, env: Env) {
    const sql = neon(env.DATABASE_URL);
    const users = await sql`SELECT * FROM users`;
    return Response.json(users);
  }
};
パターン2:Next.js で Vercel Postgres を使用
'use server';
import { sql } from '@vercel/postgres';

export async function getUsers() {
  const { rows } = await sql`SELECT * FROM users`;
  return rows;
}
パターン3:Drizzle ORM のセットアップ
// db/index.ts
import { drizzle } from 'drizzle-orm/neon-http';
import { neon } from '@neondatabase/serverless';
import * as schema from './schema';

const sql = neon(process.env.DATABASE_URL!);
export const db = drizzle(sql, { schema });

// Usage: Type-safe queries with JOINs
const postsWithAuthors = await db
  .select({ postId: posts.id, authorName: users.name })
  .from(posts)
  .leftJoin(users, eq(posts.userId, users.id));

パターン4:Neon の自動トランザクション

Neon 独自のトランザクション API(配列構文またはコールバック構文)については、ステップ5を参照してください


パターン5:プレビュー環境向けの Neon ブランチ機能
# Create branch for PR
neonctl branches create --project-id my-project --name pr-123 --parent main

# Get connection string for branch
BRANCH_URL=$(neonctl connection-string pr-123)

# Use in Vercel preview deployment
vercel env add DATABASE_URL preview
# Paste $BRANCH_URL

# Delete branch when PR is merged
neonctl branches delete pr-123
# .github/workflows/preview.yml
name: Create Preview Database
on:
  pull_request:
    types: [opened, synchronize]

jobs:
  preview:
    runs-on: ubuntu-latest
    steps:
      - name: Create Neon Branch
        run: |
          BRANCH_NAME="pr-${{ github.event.pull_request.number }}"
          neonctl branches create --project-id ${{ secrets.NEON_PROJECT_ID }} --name $BRANCH_NAME
          BRANCH_URL=$(neonctl connection-string $BRANCH_NAME)

      - name: Deploy to Vercel
        env:
          DATABASE_URL: ${{ steps.branch.outputs.url }}
        run: vercel deploy --env DATABASE_URL=$DATABASE_URL

使用する場面:PR またはプレビューのデプロイごとに分離されたデータベースが必要な場合


バンドルされたリソースの使用

スクリプト(scripts/)

setup-neon.sh - Neon データベースを作成し、接続文字列を出力します

chmod +x scripts/setup-neon.sh
./scripts/setup-neon.sh my-project-name

test-connection.ts - データベース接続を検証し、テストクエリを実行します

npx tsx scripts/test-connection.ts
リファレンス(references/)
  • references/connection-strings.md - 接続文字列の形式、プールあり・なしの完全ガイド
  • references/drizzle-setup.md - Neon での Drizzle ORM の段階的なセットアップ
  • references/prisma-setup.md - Neon アダプターを使用した Prisma のセットアップ
  • references/branching-guide.md - Neon のデータベースブランチ機能の包括的なガイド
  • references/migration-strategies.md - 各種 ORM やツール向けのマイグレーションパターン
  • references/common-errors.md - 詳細なトラブルシューティングガイド

Claude が読み込むタイミング:

  • 接続の問題をデバッグするときは connection-strings.md を読み込みます
  • ユーザーが Drizzle ORM を使いたい場合は drizzle-setup.md を読み込みます
  • ユーザーが Prisma を使いたい場合は prisma-setup.md を読み込みます
  • ユーザーがプレビュー環境やデータベースブランチ機能について尋ねた場合は branching-guide.md を読み込みます
  • 特定のエラーメッセージが発生した場合は common-errors.md を読み込みます
アセット(assets/)
  • assets/schema-example.sql - users、posts、comments を含むデータベーススキーマの例
  • assets/drizzle-schema.ts - Drizzle スキーマの完全なテンプレート
  • assets/prisma-schema.prisma - Prisma スキーマの完全なテンプレート

高度なトピック

データベースのブランチ機能(Neon 固有の機能)

Neon は Git のようなデータベースのブランチ機能を提供します。

# Create branch from main
neonctl branches create --name dev --parent main

# Create from point-in-time (PITR restore)
neonctl branches create --name restore --parent main --timestamp "2025-10-28T10:00:00Z"

# Get connection string for branch
neonctl connection-string dev

# Delete branch
neonctl branches delete feature

主な機能:

  • コピーオンライト:ブランチは即座に作成されます(データのコピーは不要です)
  • プレビューのデプロイ:PR ごとにブランチを作成し、マージ時に削除します
  • ポイントインタイムリストア:特定のタイムスタンプに復元します(無料プランでは 7 日間保持)
  • コンピューティングの共有:ブランチ間でコンピューティングの上限を共有します(無料プラン)。有料プランでは個別にコンピューティングを利用できます

パフォーマンスとセキュリティに関する注意事項

接続プールの監視:

  • Neon ダッシュボードで使用状況を確認します(接続上限:無料プランでは 100、プーリング使用時は約 10,000)
  • 使用率が 80% を超えた場合にアラートを設定します
  • 「接続プールが枯渇しました」エラーを避けるには、プール済み接続文字列を使用します

クエリの最適化:

  • 頻繁にクエリする列にはインデックスを使用します
  • N+1 クエリを避けます(JOIN または Drizzle のリレーションを使用します)
  • 繰り返し実行するクエリには Drizzle のプリペアドステートメントを使用します

セキュリティ:

  • 接続文字列をコードに直接記述しないでください(環境変数を使用します)
  • テンプレートタグ構文により SQL インジェクションを防止できます
  • マルチテナントアプリでは行レベルセキュリティ(RLS)を使用します
  • クエリの前に Zod で入力を検証します

依存関係

必須:

  • @neondatabase/serverless@^1.0.2 - Neon のサーバーレス Postgres クライアント(HTTP/WebSocket ベース)
  • @vercel/postgres@^0.10.0 - Vercel Postgres クライアント(Neon を直接使用する場合の代替、Vercel 固有)

任意:

  • drizzle-orm@^0.44.7 - TypeScript ORM(エッジ対応、推奨)
  • drizzle-kit@^0.31.7 - Drizzle のスキーママイグレーションおよびイントロスペクション
  • @prisma/client@^6.10.0 - Prisma ORM(Node.js 専用、エッジ非対応)
  • @prisma/adapter-neon@^6.10.0 - Neon サーバーレス用 Prisma アダプター
  • neonctl@^2.19.0 - データベース管理用 Neon CLI
  • zod@^3.24.0 - 入力サニタイズ用のスキーマ検証

公式ドキュメント


パッケージバージョン(2026-01-09 確認済み)

{
  "dependencies": {
    "@neondatabase/serverless": "^1.0.2",
    "@vercel/postgres": "^0.10.0",
    "drizzle-orm": "^0.45.1"
  },
  "devDependencies": {
    "drizzle-kit": "^0.31.8",
    "neonctl": "^2.19.0"
  }
}

最新の Prisma(必要な場合):

{
  "dependencies": {
    "@prisma/client": "^6.10.0",
    "@prisma/adapter-neon": "^6.10.0"
  },
  "devDependencies": {
    "prisma": "^6.10.0"
  }
}

本番環境での実績

このスキルは、Neon と Vercel Postgres の本番環境へのデプロイに基づいています。

  • Cloudflare Workers:API で毎日 50K 件以上のリクエストを処理し、接続エラーは 0 件
  • Vercel Next.js App:月間ユーザー数 100K 人以上の E コマースサイト
  • ビルド時間:5 分未満(初期セットアップ)、30 秒未満(デプロイ)
  • エラー:0 件(既知の問題 19 件をすべて防止)
  • 検証項目:✅ 接続プーリング、✅ SQL インジェクションの防止、✅ トランザクション処理、✅ ブランチを活用したワークフロー、✅ エッジランタイムとの互換性、✅ Node v20 のトランザクションパターン

トラブルシューティング

問題:Error: connection pool exhausted

解決方法:

  1. プーリングされた接続文字列(末尾が -pooler.region.aws.neon.tech)を使用していることを確認します
  2. Neon ダッシュボードで接続の使用状況を確認します
  3. 制限に頻繁に達する場合は、上位のプランにアップグレードします
  4. クエリを最適化して、接続の保持時間を短縮します
問題:Error: TCP connections are not supported

解決方法:

  • pg や postgres.js ではなく、@neondatabase/serverless を使用します
  • 従来の Postgres クライアントをインポートしていないことを確認します
  • バンドルに HTTP/WebSocket ベースのクライアントが含まれていることを確認します
問題:Error: database "xyz" does not exist

解決方法:

  • DATABASE_URL が正しいデータベースを指していることを確認します
  • Neon のブランチ機能を使用している場合は、ブランチがまだ存在することを確認します
  • 接続文字列の形式を確認します(タイプミスがないこと)
問題:コールドスタート時にクエリが遅い

解決方法:

  • Neon は無料プランでは、5 分間操作がないと自動的に一時停止します
  • 再開後の最初のクエリには約 1~2 秒かかります
  • コールドスタートを考慮し、クエリのタイムアウトを 10 秒以上に設定します
  • 常時稼働するデータベースには、有料プランで自動一時停止を無効にします
問題:PrismaClient is unable to be run in the browser

解決方法:

  • Prisma は Cloudflare Workers(V8 アイソレート)では動作しません
  • エッジに対応した ORM として Drizzle ORM を使用します
  • Prisma は @prisma/adapter-neon を使うと、Vercel Edge/Node.js ランタイムで動作します
問題:ブランチ間でのマイグレーションバージョンの競合

解決方法:

  • まずメインブランチでマイグレーションを実行します
  • マイグレーションの後にフィーチャーブランチを作成します
  • または、マージの前にブランチのスキーマをリセットします:neonctl branches reset feature --parent main
問題:drizzle-kit での「WebSocket warning」(コミュニティからの情報)

エラー:Warning: @neondatabase/serverless can only connect to remote Neon/Vercel Postgres/Supabase instances through a websocket 出典:GitHub Discussion #12508 解決方法:この警告は情報提供を目的としたもので、安全に無視できます。警告が出てもマイグレーションは正常に動作します。この警告は、WebSocket プロトコルが使用されていることをユーザーに知らせるもので、問題が発生した場合のデバッグに役立ちます。開発依存関係として pg を追加すれば警告は表示されなくなりますが、追加する必要はありません。

問題:VPN によって Neon への接続がブロックされる(コミュニティからの情報)

エラー:NeonDbError: Error connecting to database: fetch failed [cause]: SocketError: other side closed 出典:GitHub Issue #146 のコメント 解決方法:一部の VPN は、Neon のエンドポイントへの WebSocket 接続または fetch 接続をブロックします。これは主に、Next.js 14 以降のサーバーアクションを使った開発中(localhost)に発生します。VPN を無効にしてテストするか、VPN の設定で Neon のドメインを許可リストに追加します:

# Whitelist these domains in VPN:
*.neon.tech
*.aws.neon.tech

セットアップ完了チェックリスト

このチェックリストを使って、セットアップを確認してください。

  • パッケージがインストールされている(@neondatabase/serverless または @vercel/postgres)
  • Neon データベースが作成されている(または Vercel Postgres がプロビジョニングされている)
  • プーリング接続文字列を取得している(末尾が -pooler.)
  • 接続文字列に ?sslmode=require が含まれている
  • 環境変数が設定されている(DATABASE_URL または POSTGRES_URL)
  • データベーススキーマが作成されている(生の SQL、Drizzle、または Prisma)
  • クエリでテンプレートタグ構文(sql`...`)を使用している
  • トランザクションで適切な try/catch を使用し、接続を解放している
  • 接続プーリングを確認している(プーリング接続文字列を使用)
  • ランタイムに適した ORM を選択している(エッジには Drizzle、Node.js には Prisma)
  • 開発用データベースでローカルテストを実施している
  • 本番環境/プレビュー環境にデプロイし、テストしている
  • Neon ダッシュボードで接続のモニタリングを設定している

質問や問題がありますか?

  1. 詳しいトラブルシューティングについては、references/common-errors.md を確認してください
  2. 7 段階のセットアッププロセスのすべての手順を確認してください
  3. 公式ドキュメントを確認してください:https://neon.tech/docs
  4. サーバーレス環境では、必ずプーリング接続文字列を使用してください
  5. 接続文字列に sslmode=require が含まれていることを確認してください
  6. scripts/test-connection.ts で接続をテストしてください

最終確認日:2026-01-21 | スキルのバージョン:2.0.0 | 変更内容:新たな問題を 4 件追加(#16~#19:poolQueryViaFetch、Node v20 のトランザクション、process.env のサンドボックス化);移行ガイド(v0.x→v1.0+)を追加;パフォーマンスとプロトコル選択のセクションを追加;問題 #11 に自動一時停止の処理と本番環境の設定を追加;コミュニティから寄せられたトラブルシューティング(WebSocket の警告、VPN によるブロック)をティア 2 に追加

コメント