api-baas-neon について
Neon のサーバーレス PostgreSQL ドライバーを使う開発者向けのスキルです。エッジやサーバーレス環境でのクエリ、接続管理、安全な SQL、データベース分岐を扱います。
主な機能
- 01`neon()` による HTTP クエリ
- 02WebSocket プールとクライアント
- 03HTTP によるアトミックなトランザクション
- 04プール接続と直接接続の使い分け
- 05データベース分岐のパターン
- 06コールドスタートへの対応
活用シーン
- 01エッジ関数から PostgreSQL を照会
- 02サーバーレスハンドラーでトランザクションを実行
- 03開発・プレビュー用ブランチを作成
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ agents-inc/ skills --skill api-baas-neonインストール後、Claude Code で/api-baas-neonを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
metadata.yamlreference.mdexamples/branching.mdcore.md詳細
Neon Serverless PostgreSQL のパターン
クイックガイド: エッジ/サーバーレス環境からデータベースにアクセスするには、
@neondatabase/serverlessを使用します。単一のクエリにはneon()HTTP 関数を優先してください(高速でステートレスです)。対話型トランザクションにはPool/Clientを使用します。サーバーレスのワークロードには、プール済み接続文字列(-pooler接尾辞)を使用し、直接接続はマイグレーションにのみ使用してください。コピーオンライト方式を使用して、開発/プレビュー環境用にデータベースをブランチ分岐します。ゼロへのスケールダウンからのコールドスタート(起動に 200~500ms)には、必ず対処してください。
<critical_requirements>
重要:このスキルを使用する前に
(エッジ/サーバーレスのランタイムで単一のクエリを実行するには、必ず neon() HTTP 関数を使用してください。1 回限りの操作では WebSocket より 2~3 倍高速です)
(サーバーレス環境では、Pool/Client の接続を同じリクエストハンドラー内で必ず閉じてください。WebSocket 接続を 1 つのリクエストの完了後も維持することはできません)
(サーバーレスのワークロードには、必ずプール済み接続文字列(-pooler 接尾辞)を使用してください。直接接続では、限られた接続枠を使い切ってしまいます)
(適切な接続タイムアウトと再試行ロジックを使用して、ゼロへのスケールダウンからの起動遅延(200~500ms)に必ず対処してください)
(sql.unsafe() は、テーブル名やカラム名など、信頼できる安全性が確認された文字列にのみ使用してください。ユーザー入力には決して使用しないでください)
</critical_requirements>
自動検出: Neon、@neondatabase/serverless、neon()、neonConfig、Neon サーバーレスドライバー、Neon データベース、Neon ブランチ、neonctl、Neon 接続プーリング、Neon のゼロへのスケールダウン、Neon オートスケーリング、Neon PostgreSQL、ep-*-pooler
使用する場面:
- エッジ/サーバーレス関数(エッジランタイム、サーバーレスプラットフォーム)から Postgres にクエリを実行する
- さまざまなワークロード向けに接続文字列(プール済み/直接)を設定する
- 開発、プレビュー、CI 環境用にデータベースブランチを作成する
- ゼロへのスケールダウンの動作を管理し、コールドスタートを最適化する
- サーバーレスのコンテキストでトランザクションを実行する(HTTP バッチまたは WebSocket)
- Neon API または neonctl CLI を使用して、プログラムからブランチを管理する
対象となる主なパターン:
- SQL タグ付きテンプレートと合成可能なフラグメントを使用した
neon()HTTP クエリ - 適切なライフサイクル管理を伴う
Pool/ClientWebSocket 接続 - プール済み(
-pooler)接続文字列と直接接続文字列、およびそれぞれの使い分け - データベースのブランチ分岐(開発ブランチ、PR プレビューブランチ、スキーマのみのブランチ)
- ゼロへのスケールダウンの動作、コールドスタートの軽減、オートスケーリング
- 対話を伴わない HTTP トランザクションのための
sql.transaction() - プログラムからのブランチ管理に使用する Neon API と neonctl CLI
使用しない場面:
- 従来型の長時間稼働するサーバー接続(TCP を使用する標準の
pgドライバーを使用してください) - ORM 固有の複雑なパターン(使用する ORM の専用スキルを使用してください)
- 一般的な PostgreSQL クエリ構文(SQL/Postgres のスキルを使用してください)
詳細なリソース:
- 判断フレームワークとクイック参照表については、reference.md を参照してください
ドライバーとクエリ:
- examples/core.md -- ドライバーのセットアップ、HTTP クエリ、WebSocket 接続、トランザクション
ブランチ分岐と運用:
- examples/branching.md -- 開発ブランチ、PR プレビュー、neonctl CLI、Neon API、CI/CD ワークフロー
## 哲学
Neon は PostgreSQL のストレージとコンピュートを分離し、従来の Postgres では実現できないサーバーレス機能(スケールトゥゼロ、即時ブランチ、自動スケーリング)を可能にします。@neondatabase/serverless ドライバーは TCP を HTTP と WebSockets に置き換え、TCP をサポートしないエッジランタイムから Postgres にアクセスできるようにします。
基本原則:
- 速度には HTTP、セッションには WebSocket --
neon()関数は単一クエリに HTTP fetch(約 3 往復)を使用します。セッションやインタラクティブなトランザクションが必要な場合、Pool/Clientは WebSockets(約 8 往復)を使用します。用途に適したトランスポートを選択してください。 - デフォルトでプーリング -- プールされた接続は PgBouncer(トランザクションモード)を経由し、最大 10,000 の同時クライアントを処理します。直接接続はコンピュートサイズ(100~4,000)によって制限され、マイグレーションまたはセッション状態が必要な機能にのみ使用してください。
- ブランチは低コスト -- コピーオンライト方式により、500GB のデータベースのブランチは、データが分岐するまで追加ストレージを割り当てません。開発、プレビュー、テスト、CI でブランチを自由に活用してください。
- スケールトゥゼロがデフォルト -- コンピュートは 5 分間操作がないと一時停止します。コールドスタートには 200~500ms かかります。タイムアウト、再試行、接続プーリングを使って、この動作に備えて設計してください。
- SQL インジェクション対策を標準搭載 -- タグ付きテンプレート関数は値を自動的にパラメーター化します。v1.0 以降、
neon()を通常の関数として呼び出すと型エラーになり、誤ったインジェクションを防止します。
Neon サーバーレスドライバーを使用する場合:
- TCP 接続を開けないエッジ/サーバーレス関数
- データベースのブランチ機能が役立つアプリケーション(PR ごとのプレビュー環境など)
- スケールトゥゼロの恩恵を受ける、コスト重視のワークロード
- 接続プーリングを必要とする、高い同時実行性を備えたサーバーレスアプリ
使用しない場合:
- 永続的な接続を使う、長時間実行されるサーバープロセス(TCP 経由の標準的な
pgを使用してください) - PgBouncer 経由でセッションレベルの機能(LISTEN/NOTIFY、SET、一時テーブル)を必要とするワークロード
- 常時稼働のコンピュートが必要な 16 CU 超のデータベース(16 CU を超えるとスケールトゥゼロは利用できません)
基本パターン
パターン 1:neon() を使った HTTP クエリ
neon() 関数は、SQL タグ付きテンプレートを使って HTTP ベースのクエリ関数を作成します。単一のインタラクティブでないクエリを実行する最速の方法です。
import { neon } from "@neondatabase/serverless";
const DATABASE_URL = process.env.DATABASE_URL!;
const sql = neon(DATABASE_URL);
// Tagged template -- parameters are auto-parameterized (safe from injection)
const userId = "abc-123";
const posts =
await sql`SELECT id, title FROM posts WHERE author_id = ${userId}`;
利点: タグ付きテンプレートが値を自動的にパラメーター化して SQL インジェクションを防ぎます。HTTP は WebSocket の約 8 往復に対して約 3 往復です。また、ステートレスなので管理する接続がありません。
// BAD: Calling neon() as a regular function (v1.0+ type error)
const sql = neon(DATABASE_URL);
const result = await sql(`SELECT * FROM posts WHERE id = ${id}`); // TYPE ERROR + SQL injection risk
注意点: v1.0 以降、クエリ関数を通常の関数として(タグ付きテンプレートではなく)呼び出すと、実行時エラーおよび型エラーになります。文字列補間による SQL インジェクションを防ぐために、意図的に変更されました。
動的 SQL に対する sql.query()
クエリ文字列が変数に格納されている場合(テンプレートリテラルではない場合)は、番号付きプレースホルダーを使う .query() メソッドを使用します。
const q = "SELECT * FROM posts WHERE id = $1 AND status = $2";
const posts = await sql.query(q, [postId, "published"]);
使用する場合: 実行時に構築する動的 SQL 文字列、または変数に格納されたクエリ。パラメーターは $1、$2 などを使って引き続き安全にパラメーター化されます。
パターン 2:合成可能なクエリフラグメント
テンプレートクエリは、フラグメント間でパラメーター番号を自動的に割り当てながら合成できます。
import { neon } from "@neondatabase/serverless";
const sql = neon(DATABASE_URL);
// Build queries from reusable fragments
const whereClause = sql`WHERE status = ${"active"} AND role = ${"admin"}`;
const orderClause = sql`ORDER BY created_at DESC`;
const PAGE_SIZE = 20;
const limitClause = sql`LIMIT ${PAGE_SIZE}`;
const users =
await sql`SELECT id, name, email FROM users ${whereClause} ${orderClause} ${limitClause}`;
利点: 合成されたフラグメント間でパラメーター番号が自動的に振り直されます。ページサイズを名前付き定数にでき、フラグメントを複数のクエリで再利用できます。
sql.unsafe() を使った動的なテーブル名/カラム名
// ONLY for trusted, known-safe values -- never user input
const TABLE_NAME = "posts";
const results =
await sql`SELECT * FROM ${sql.unsafe(TABLE_NAME)} WHERE id = ${postId}`;
使用する場合: SQL でパラメーター化できない、信頼できる識別子(テーブル名、カラム名)を補間する必要がある場合に限ります。ユーザー指定の値を sql.unsafe() に渡してはいけません。
パターン 3:sql.transaction() による HTTP トランザクション
WebSocket 接続なしで、HTTP 経由で複数のクエリをアトミックに実行します。
import { neon } from "@neondatabase/serverless";
const sql = neon(DATABASE_URL);
// Array form -- all queries execute in a single HTTP round trip
const [posts, totalCount] = await sql.transaction([
sql`SELECT id, title FROM posts ORDER BY created_at DESC LIMIT 10`,
sql`SELECT count(*) FROM posts`,
]);
// Function form with transaction options
const [, transferResult] = await sql.transaction(
(txn) => [
txn`UPDATE accounts SET balance = balance - ${amount} WHERE id = ${fromId}`,
txn`UPDATE accounts SET balance = balance + ${amount} WHERE id = ${toId}`,
],
{ isolationLevel: "Serializable" },
);
利点: WebSocket のオーバーヘッドなしでアトミックに実行でき、配列形式は読み取り専用のバッチ処理で簡潔に記述できます。関数形式ではトランザクションオプションを指定でき、分離レベルによって一貫性の保証を制御できます。
// BAD: Running related queries as separate HTTP requests
const posts = await sql`SELECT * FROM posts WHERE author_id = ${authorId}`;
const author = await sql`SELECT * FROM users WHERE id = ${authorId}`;
// Two separate HTTP round trips, not atomic, race conditions possible
欠点: HTTP 呼び出しを個別に行う場合、アトミックではありません。クエリ間にデータが変更される可能性があり、ネットワーク遅延も 2 倍になります。
トランザクションオプション
isolationLevel:ReadUncommitted|ReadCommitted|RepeatableRead|SerializablereadOnly:ブール値(デフォルトはfalse)deferrable:ブール値(デフォルトはfalse。readOnly: trueとSerializableを併用した場合のみ有効)
パターン 4:Pool/Client による WebSocket 接続
インタラクティブなトランザクションや node-postgres API との互換性が必要な場合は、Pool と Client を使用します。サーバーレス環境では、接続を単一のリクエストハンドラー内で作成し、閉じる必要があります。
import { Pool } from "@neondatabase/serverless";
export async function handleRequest(request: Request): Promise<Response> {
const pool = new Pool({ connectionString: process.env.DATABASE_URL });
try {
// ... queries ...
} finally {
await pool.end(); // ALWAYS close within the same request
}
}
重要なルール: ハンドラー内で Pool を作成し、finally で pool.end() を呼び出して閉じます。グローバルな Pool を使うと、サーバーレスの呼び出し間で WebSocket 接続がリークします。
リクエスト単位のプール、インタラクティブなトランザクション、Node.js の WebSocket 設定については、examples/core.md のパターン 5~7 を参照してください。
パターン 5:接続文字列の設定
Neon では、プーリング接続(PgBouncer 経由)と直接接続の 2 種類の接続文字列を利用できます。
# Pooled connection (note: -pooler suffix on endpoint ID)
# Use for: serverless functions, web apps, high-concurrency workloads
DATABASE_URL=postgresql://user:[email protected]/dbname?sslmode=require
# Direct connection (no -pooler suffix)
# Use for: migrations, pg_dump, LISTEN/NOTIFY, session-level features
DIRECT_DATABASE_URL=postgresql://user:[email protected]/dbname?sslmode=require
利点: プーリング接続ではトランザクションモードの PgBouncer 経由で最大 10,000 のクライアントを処理でき、直接接続では管理タスク向けにセッションの全機能を利用できます。環境変数を分けることで、その違いが明確になります。
PgBouncer のトランザクションモードの制限事項
プーリング接続では、PgBouncer がトランザクションモードで動作します。つまり、接続は各トランザクションの終了後にプールへ戻されます。そのため、次の機能は使用できません。
SET/RESET文(代わりにALTER ROLE ... SETを使用してください)LISTEN/NOTIFYWITH HOLD CURSOR- SQL レベルの
PREPARE/DEALLOCATE(プロトコルレベルのプリペアドステートメントは最大 1,000 個までサポートされます) PRESERVE/DELETE ROWSを指定した一時テーブル- セッションレベルのアドバイザリロック
パターン 6:コールドスタートとスケール・トゥ・ゼロへの対応
Neon の自動サスペンドは、デフォルトでは 5 分間操作がない場合に実行されます。コールドスタートには 200~500 ミリ秒かかります。適切なタイムアウトと再試行ロジックを設定して、この動作に備えてください。
const CONNECTION_TIMEOUT_MS = 10_000;
const sql = neon(process.env.DATABASE_URL!, {
fetchOptions: { signal: AbortSignal.timeout(CONNECTION_TIMEOUT_MS) },
});
重要なルール: コールドスタートの遅延に対応できるよう、明示的にタイムアウト(10~15 秒)を設定してください。信頼性を高めるには、指数バックオフによる再試行を使用してください。
タイムアウトの完全な設定と再試行パターンについては、examples/core.md のパターン 8 を参照してください。
スケール・トゥ・ゼロに関する事実
- デフォルトの自動サスペンド:5 分間操作がない場合
- コールドスタートの遅延:約 200~500 ミリ秒(リージョンとコンピュートサイズによって異なります)
- 16 CU までのコンピュートでのみ利用可能(それより大きいコンピュートは常時稼働します)
- 有料プランではサスペンドまでのタイムアウトを調整(最大 7 日)するか、完全に無効化できます
- 論理レプリケーションのサブスクライバーがアクティブな場合、サスペンドは実行されません
パターン 7:データベースのブランチング
Neon のブランチはコピーオンライト方式を採用しているため、500 GB のデータベースでも瞬時にブランチを作成でき、データが分岐するまでは追加のストレージを割り当てません。
# Install neonctl
npm install -g neonctl
# Create a dev branch from main
neonctl branches create --name dev-alice --project-id <project-id>
# Create a branch with automatic expiration (for CI/preview)
neonctl branches create --name preview/pr-42 --project-id <project-id> --expires-at "2025-04-01T00:00:00Z"
# Create schema-only branch (no data copied -- for sensitive environments)
neonctl branches create --name ci-test --schema-only --project-id <project-id>
# Reset a dev branch to match current production
neonctl branches reset dev-alice --parent --project-id <project-id>
# Delete a branch
neonctl branches delete preview/pr-42 --project-id <project-id>
利点: 名前付きブランチを Git のワークフローに対応させられ、TTL の有効期限によって CI ブランチが自動的にクリーンアップされます。スキーマのみのブランチングで機密データを保護でき、リセットによってデータベースを再作成せずに開発環境を本番環境と同期できます。
ブランチの接続文字列
各ブランチには専用のエンドポイントが割り当てられます。ブランチの接続文字列は同じ形式ですが、エンドポイント ID が異なります。
# Main branch
postgresql://user:[email protected]/dbname
# Dev branch -- different endpoint ID
postgresql://user:[email protected]/dbname
パターン 8:Neon API によるプログラムからのブランチ管理
Neon REST API(https://console.neon.tech/api/v2)を使用すると、プログラムからブランチを管理できます。Authorization: Bearer <NEON_API_KEY> で認証します。主な操作:TTL の有効期限を設定したブランチの作成、ブランチの削除、クリーンアップスクリプト用のブランチ一覧取得。
const NEON_API_BASE = "https://console.neon.tech/api/v2";
// POST /projects/{projectId}/branches -- create with { branch: { name, expires_at }, endpoints: [{ type: "read_write" }] }
// DELETE /projects/{projectId}/branches/{branchId} -- delete a branch
完全な型付き TypeScript ブランチマネージャー(作成、削除、一覧取得の各操作を含む)については、examples/branching.md のパターン 3 を参照してください。 API エンドポイントの完全な一覧については、reference.md を参照してください。
<decision_framework>
選択の指針
HTTP(neon())と WebSocket(Pool/Client)
What kind of database operation?
+-- Single query (SELECT, INSERT, UPDATE, DELETE)
| +-- YES --> Use neon() HTTP function (fastest, ~3 round trips)
+-- Multiple queries that must be atomic?
| +-- Can all queries be determined upfront (non-interactive)?
| | +-- YES --> Use sql.transaction() over HTTP
| | +-- NO --> Use Pool/Client over WebSocket
+-- Need node-postgres (pg) API compatibility?
| +-- YES --> Use Pool/Client over WebSocket
+-- Running in edge runtime (no TCP)?
+-- YES --> Use @neondatabase/serverless (HTTP or WebSocket)
+-- NO --> Standard pg driver with TCP may be simpler
プール接続と直接接続
What is the workload?
+-- Serverless function / edge function --> Pooled (-pooler)
+-- Web application (many concurrent requests) --> Pooled (-pooler)
+-- Schema migration --> Direct (needs session state)
+-- pg_dump / pg_restore --> Direct (uses SET statements)
+-- LISTEN / NOTIFY --> Direct (session-level feature)
+-- Long-running analytics query --> Direct (avoid pool contention)
+-- Default / unsure --> Pooled (-pooler)
ブランチ戦略
What do you need the branch for?
+-- Developer working on a feature --> Dev branch (long-lived, manually managed)
+-- PR preview environment --> Preview branch (TTL expiration, auto-cleanup on merge)
+-- CI test run --> Ephemeral branch (short TTL, schema-only if data-sensitive)
+-- Database recovery --> Restore from branch history (up to 30 days on Scale plan)
+-- Load testing --> Branch from production (copy-on-write, no storage cost until diverge)
</decision_framework>
<red_flags>
危険な兆候
優先度の高い問題:
- サーバーレス環境でのグローバルな
Pool— エッジ/サーバーレス関数でリクエストハンドラーの外にPoolを作成すると、WebSocket 接続がリークします。Pool/Clientは、1 回のリクエスト内で作成、使用、クローズする必要があります。 - サーバーレス環境での直接接続文字列の使用 — 直接接続は PgBouncer を経由せず、コンピュートサイズに応じた最大接続数(100~4,000)に制限されます。サーバーレス関数では、必ずプーリング接続(
-pooler)を使用してください。 - ユーザー入力を
sql.unsafe()に渡す —sql.unsafe()は、パラメーター化せずに生の SQL を埋め込みます。信頼できる識別子(テーブル名/列名)にのみ使用するものです。sql.unsafe()にユーザー入力を渡すと、SQL インジェクションの脆弱性につながります。
優先度が中程度の問題:
- 二重プーリング — Neon のサーバー側 PgBouncer と、ドライバーのクライアント側接続プールを組み合わせると、不要なオーバーヘッドが発生します。プーリングは Neon に任せてください。
- サーバーレス環境での
pool.end()の呼び出し忘れ — WebSocket 接続の使用後にpool.end()を呼び忘れると、呼び出しをまたいで利用可能な接続が枯渇します。 - プーリング接続を介した
SET文の使用 — PgBouncer のトランザクションモードでは、トランザクションごとにセッション状態がリセットされます。ロールレベルのデフォルト値にはALTER ROLE ... SETを使用するか、直接接続を使用してください。 - コールドスタートのレイテンシーへの未対処 — アイドル期間後の最初のリクエストでは、200~500ms の遅延が加わります。適切なタイムアウト(10 秒以上)と再試行ロジックがないと、アプリケーションで断続的な障害が発生します。
よくある間違い:
- パッケージ名の誤り — パッケージ名は
@neondatabase/serverlessです。neon-serverlessやpg-neonではありません。 - Node.js <= v21 での
wsパッケージの不足 — v22 より前の Node.js には WebSocket の組み込みサポートがありません。Pool/Clientを使用する場合は、wsをインストールし、neonConfig.webSocketConstructor = wsを設定してください。Node.js v22 以降はネイティブの WebSocket を備えているため、追加の設定は不要です。 neon()の戻り値をタグ付きテンプレートではなく関数として呼び出す — v1.0 以降、sql("SELECT ...")は型エラーになります。sql`SELECT ...`(タグ付きテンプレート)を使用してください。- サーバーレス環境の呼び出しをまたいで
Poolが存続すると期待する — コールドスタートのたびに新しい実行コンテキストが作成されます。接続管理にグローバル状態を頼らないでください。 - 64MB のリクエスト/レスポンス制限 — HTTP モードのペイロード上限は 64MB です。大きな結果セットや一括挿入は、分割して処理する必要があります。
注意点とエッジケース:
- トランザクションオプションは個々のクエリではなく、トランザクションに適用される —
sql.transaction()内の個々のクエリにarrayMode: trueを設定しても無視されます。トランザクション自体に設定してください。 - PgBouncer のクエリ待機タイムアウトは 120 秒 — すべてのプーリング接続が使用中の場合、新しいクエリはタイムアウトするまで最大 120 秒間キューに入ります。
- ブランチのエンドポイントは親のものとは異なる — 各ブランチには固有のエンドポイント ID が割り当てられます。親の接続文字列を使って子ブランチに接続することはできません。
- ゼロスケールの対象は 16 CU 以下のコンピュートのみ — 16 CU を超えるコンピュートは、設定にかかわらず常時稼働します。
- 論理レプリケーションはサスペンドを妨げる — アクティブなレプリケーションサブスクライバーがコンピュートを稼働状態に保ち、ゼロスケールが適用されなくなります。
- スキーマのみのブランチ —
neonctl branches create --schema-onlyまたは"init_source": "schema-only"を指定した REST API を使用してください。スキーマのみのブランチでは、読み書き可能なコンピュートエンドポイントが正確に 1 つ必要です。 - ブランチ履歴には保持期間がある — Free プラン:6 時間。Launch:7 日間。Scale:30 日間。この期間を超えて復元することはできません。
- Node.js v19 以降が必要 — GA バージョンの
@neondatabase/serverless(v1.0 以降)には、Node.js 19 以降が必要です。
</red_flags>
<critical_reminders>
重要な注意事項
(エッジ/サーバーレスのランタイムで単一クエリを実行する場合は、必ず neon() HTTP 関数を使用してください。単発の操作では、WebSocket よりも2~3倍高速です)
(サーバーレス環境では、必ず同じリクエストハンドラー内で Pool/Client の接続を閉じてください。WebSocket 接続は単一のリクエストを超えて存続できません)
(サーバーレスのワークロードでは、必ずプールされた接続文字列(-pooler サフィックス)を使用してください。直接接続すると、限られた接続枠を使い切ってしまいます)
(スケール・トゥ・ゼロからの起動による遅延(200~500ms)には、適切な接続タイムアウトとリトライロジックで必ず対処してください)
(sql.unsafe() は、テーブル名やカラム名など、信頼できる安全性が確認された文字列に限って使用してください。ユーザー入力には絶対に使用しないでください)
これらのルールに従わないと、接続の枯渇、SQL インジェクションの脆弱性、またはコールドスタート時の断続的な障害が発生します。