netlify-database について
Netlify プロジェクトでマネージド Postgres を使うためのスキルです。クエリ、マイグレーション、Drizzle 連携、ローカル開発、データベース CLI の手順を説明します。
主な機能
- 01マネージド Postgres のセットアップ
- 02パラメーター化 SQL クエリ
- 03マイグレーションの生成とデプロイ
- 04Drizzle ORM アダプターの案内
- 05ローカルデータベースと CLI の手順
活用シーン
- 01Netlify プロジェクトへの Postgres 導入
- 02Functions やビルドからのデータ照会
- 03マイグレーションによるスキーマ変更管理
- 04ローカルデータベースを使った開発とテスト
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ netlify/ context-and-tools --skill netlify-databaseインストール後、Claude Code で/netlify-databaseを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/cli-commands.mdlegacy-extension.mdlocal-dev.mdmigration-from-extension.mdmigrations.mdoperational-footguns.md詳細
Netlify Database
設定不要のマネージド Postgres です。@netlify/database をインストールし、netlify/database/migrations/ にマイグレーションを記述してデプロイすると、Netlify がデータベースをプロビジョニングし、マイグレーションを自動的に適用します。Functions、Edge Functions、Builds、Agent Runners からクエリを実行できます。
最新のクライアント(こちらを使用してください)
import { getDatabase } from "@netlify/database";
const db = getDatabase(); // auto-selects connection for the runtime
const userId = 42;
const users = await db.sql`SELECT * FROM users WHERE id = ${userId}`; // auto-parameterized
独自のドライバー/ORM を使う場合はこちらです:
import { getConnectionString } from "@netlify/database";
const connectionString = getConnectionString(); // correct branch for this env
レガシー — 新しいコードでは使用しないでください: import { neon } from "@netlify/neon"。@netlify/database に置き換えられました。neon() の呼び出しは、Drizzle の netlify-db アダプター、または getConnectionString() 経由の Postgres ドライバーに置き換えてください。レガシー環境変数の NETLIFY_DATABASE_URL は NETLIFY_DB_URL に置き換えられています。
各要素の配置場所
| 内容 | 場所 |
|---|---|
| マイグレーション | netlify/database/migrations/(SQL ファイル、または migration.sql を含むサブディレクトリ) |
| クエリコード | Functions(netlify/functions/)、Edge Functions |
| Drizzle スキーマ | db/schema.ts(慣例) |
| Drizzle クライアント | db/index.ts(慣例) |
| 接続文字列 | NETLIFY_DB_URL 環境変数、または getConnectionString() |
クエリの実行
getDatabase(options?) は、sql と pool を備えたクライアントを返します。options.connectionString で自動プロビジョニングされた接続文字列を上書きでき、options.debug でログを有効にできます。
const db = getDatabase();
const active = await db.sql`SELECT * FROM users WHERE active = ${true}`;
await db.sql`INSERT INTO users (name, email) VALUES (${"Ada"}, ${"[email protected]"})`;
await db.sql`UPDATE users SET name = ${"Ada Lovelace"} WHERE id = ${1}`;
await db.sql`DELETE FROM users WHERE id = ${1}`;
// Type the rows
interface User { id: number; name: string; email: string; }
const typed = await db.sql<User>`SELECT * FROM users`;
// Stream
for await (const row of db.sql`SELECT * FROM users`.stream()) { /* ... */ }
for await (const chunk of db.sql`SELECT * FROM users`.chunked(100)) { /* ... */ }
SQLTemplate のメソッド:execute() → Promise<T[]>、stream() → AsyncGenerator<T>、chunked(n) → AsyncGenerator<T[]>、toSQL() → 実行せずに生 SQL とパラメーターを返します。
sql ヘルパー:
sql.identifier(value)— 安全なテーブル名/カラム名です。文字列、string[]、または{ schema, table, column, as }を指定できます。sql.values(rows)— 2 次元配列から一括挿入用の値リストを作成します。sql.default— SQL のDEFAULTキーワードです。sql.raw(value)— パラメーター化されていない SQL を挿入し、インジェクション保護を回避します。信頼できる定数(例:"DESC")にのみ使用し、ユーザー入力には絶対に使用しないでください。sql.unsafe(query, params?, { rowMode })—$1パラメーターを使用する生のクエリ文字列です。rowModeは"array"または"object"です。
トランザクション — pool を使用
db.pool は pg.Pool です。BEGIN/クエリ/COMMIT は同じ接続で実行する必要があります:
const client = await db.pool.connect();
try {
await client.query("BEGIN");
await client.query("INSERT INTO users (name, email) VALUES ($1, $2)", ["Ada", "[email protected]"]);
await client.query("INSERT INTO posts (author_id, title) VALUES ($1, $2)", [1, "First post"]);
await client.query("COMMIT");
} catch (e) {
await client.query("ROLLBACK");
throw e;
} finally {
client.release();
}
独自のドライバー:
import { getConnectionString } from "@netlify/database";
import pg from "pg";
const pool = new pg.Pool({ connectionString: getConnectionString() });
// or the `postgres` driver via env var
import postgres from "postgres";
const sql = postgres(process.env.NETLIFY_DB_URL);
Drizzle ORM
両方のパッケージを @beta からインストールしてください。必須です。 latest には drizzle-orm/netlify-db アダプターが含まれていないため、失敗します。
npm install @netlify/database drizzle-orm@beta
npm install -D drizzle-kit@beta
drizzle.config.ts — Netlify が生成されたマイグレーションを適用できるように、out を Netlify のマイグレーションディレクトリに設定する必要があります:
import { defineConfig } from "drizzle-kit";
export default defineConfig({
dialect: "postgresql",
schema: "./db/schema.ts",
out: "netlify/database/migrations", // NOT the default "drizzle"
});
import { pgTable, serial, text, timestamp } from "drizzle-orm/pg-core";
export const users = pgTable("users", {
id: serial().primaryKey(),
name: text().notNull(),
email: text().notNull().unique(),
createdAt: timestamp().defaultNow(),
});
import { drizzle } from "drizzle-orm/netlify-db"; // native adapter, auto-configured
import * as schema from "./schema";
export const db = drizzle({ schema });
import { desc } from "drizzle-orm";
import type { Config, Context } from "@netlify/functions";
import { db } from "../../db";
import { users } from "../../db/schema";
export default async (req: Request, context: Context) => {
if (req.method === "GET") {
const allUsers = await db.select().from(users).orderBy(desc(users.createdAt));
return Response.json(allUsers);
}
if (req.method === "POST") {
const { name, email } = await req.json();
const [user] = await db.insert(users).values({ name, email }).returning();
return Response.json(user, { status: 201 });
}
return new Response("Method not allowed", { status: 405 });
};
export const config: Config = { path: "/api/users" };
スキーマを編集した後、マイグレーションを生成します:npx drizzle-kit generate。
Netlify がホストするデータベースに対して drizzle-kit push を実行してはならず、NETLIFY_DB_URL に対して drizzle-kit migrate を実行してもいけません。 スキーマがホストされたデータベースに反映されるのは、コミットされたマイグレーションファイルがデプロイ時に適用される場合のみです。generate はファイルを書き込み、デプロイ時にそれらが適用されます。
マイグレーション
ファイルは netlify/database/migrations/ にあります。形式は 2 種類です。
netlify/database/migrations/20260301143000_create_users.sql # single SQL file
netlify/database/migrations/20260318091500_add_posts/migration.sql # subdir form
命名規則:<number>_<slug> — number は順序を定義する数字(タイムスタンプまたは 0001…)、slug は小文字の英字/数字/ハイフン/アンダースコアです。辞書順で並べられ、順番に適用されます。順序が前後した場合の拒否を避けるため、タイムスタンプのプレフィックスを使用してください(netlify database migrations new が処理します)。
CREATE TABLE comments (
id SERIAL PRIMARY KEY,
post_id INTEGER NOT NULL REFERENCES posts(id),
author_id INTEGER NOT NULL REFERENCES users(id),
body TEXT NOT NULL,
created_at TIMESTAMP DEFAULT NOW()
);
適用されるタイミング:
- 本番デプロイ:公開の直前に適用されます。失敗すると公開がブロックされます。自動公開がオフの場合、Netlify は手動で公開されるまで適用を待ちます。
- デプロイプレビュー:公開前に、デプロイごとに適用されます。失敗するとデプロイも失敗します。
- ローカル:自動では適用されません。自分で
netlify database migrations applyを実行してください。
マイグレーションでの注意点(すべてドリフトとして検出され、拒否されます):
- 適用済みのマイグレーションは編集しないでください — チェックサムのドリフト:
migration "<name>" has been modified after being applied。修正用の新しいマイグレーションを作成してください。 - 適用済みのマイグレーションは削除しないでください —
... has been removed after being applied。復元してください。 - 順序が前後した場合: プレフィックスが適用済みの最も大きなバージョン以下の場合、拒否されます。タイムスタンプを使うとこれを避けられます。
- 後方互換性のあるマイグレーションを優先してください。破壊的変更(列の名前変更/削除)は、複数回のデプロイにわたる拡張と縮小の手順にします。新しいテーブル/NULL 許容列なら、1 回のマイグレーションで問題ありません。
独自のマイグレーションシステムを使用する場合:自動検出を避けるため、netlify/database/migrations 以外のディレクトリを選び、プレビューブランチと本番環境への適用は自分で行ってください。
references/migrations.md を参照してください。
ローカル開発
ローカルでは、すべてのコードが接続するデータベースは1 つです。ブランチはデプロイ時の概念であり、ローカルには存在しません。本番環境を反映した Postgres 互換の実際のエンジンですが、単一プロセスです(負荷テストには使用できません)。自動スケール/スリープの設定は適用されません。
起動方法 — どちらの方法でも状態は共通です:
netlify dev # CLI starts + tears down the local DB
または Vite プラグイン:
import { defineConfig } from "vite";
import netlify from "@netlify/vite-plugin";
export default defineConfig({ plugins: [netlify()] });
よく使うコマンド(ローカル DB の実行中):
netlify database migrations apply # apply pending locally
netlify database migrations new -d "add users table" # scaffold new migration
netlify database migrations pull # overwrite local migrations from remote
netlify database status # enabled? installed? applied/pending migrations
netlify database connect # interactive SQL REPL
netlify database connect --query "SELECT * FROM users LIMIT 10"
netlify database reset # drop all schemas/tables — LOCAL ONLY
netlify database migrations reset # delete unapplied local migration files
外部ツール(netlify dev の実行中に使用可能):
psql "$(netlify database connect --json | jq -r .connection_string)"
references/local-dev.md を参照してください。
セットアップ
新規プロジェクト:アプリについて Agent Runners に https://app.netlify.com/start で説明するか、ローカルで netlify create "<description>" を実行します。
既存のプロジェクト:
netlify database init # installs @netlify/database, picks Drizzle or raw SQL, scaffolds a migration
netlify database init --yes # non-interactive (CI / agents)
netlify dev
手動で行う場合:npm install @netlify/database を実行し、netlify/database/migrations/ にマイグレーションを作成し、関数を作成して、netlify dev を実行し、デプロイします。
@netlify/database がインストールされていない場合、Netlify はデータベースを自動でプロビジョニングしません — UI の Data & Storage > Database メニューから手動で作成する必要があります。パッケージをインストールしてください。
CLI リファレンス(netlify database)
前提条件:Node ≥ 20.12.2、Netlify CLI ≥ 26.0.0(npm install -g netlify-cli)。すべてのコマンドで --json を使用できます。
| コマンド | 用途 | 主なフラグ |
|---|---|---|
init | プロジェクトに DB をセットアップ | -y, --yes |
status | 状態:有効化、インストール、接続文字列、適用済み/保留中のマイグレーション | -b, --branch、--show-credentials |
connect | SQL REPL、または --query による単発実行 | -q, --query、--json |
migrations apply | ローカル DB に保留中のマイグレーションを適用 | --to <name> |
migrations new | マイグレーションのひな型を作成 | -d, --description、-s, --scheme sequential|timestamp |
migrations pull | ブランチからローカルファイルを上書き | -b, --branch、--force |
migrations reset | 未適用のローカルマイグレーションファイルを削除 | -b, --branch |
reset | すべてのデータ/テーブルを削除 — ローカルのみ | — |
references/cli-commands.md を参照してください。
REST API
サイトをスコープとし、ルートは https://api.netlify.com/api/v1 です。OAuth 2。完全なリファレンス:https://open-api.netlify.com。
| メソッド + パス | 目的 |
|---|---|
POST /sites/{site_id}/database | DB を作成します(既存の接続文字列がある場合はそれを返します)。region は省略可能です |
GET /sites/{site_id}/database | 接続文字列を取得します |
POST /sites/{site_id}/database/branch | ブランチを作成します。本文は deploy_id(必須)、parent_branch_id(省略可能。デフォルトは production)です |
GET /sites/{site_id}/database/branch/{deploy_id} | ブランチの接続文字列を取得します(存在しない場合は 404) |
DELETE /sites/{site_id}/database/branch/{deploy_id} | デプロイのブランチを削除します |
POST /sites/{site_id}/database/snapshot | ブランチのスナップショットを作成します(デフォルトは production) |
GET /sites/{site_id}/database/snapshots | スナップショットの一覧を取得します |
DELETE /sites/{site_id}/database/snapshot/{snapshot_id} | スナップショットを削除します |
POST /sites/{site_id}/database/snapshot/{snapshot_id}/restore | スナップショットをブランチに復元します(デフォルトは production) |
ブランチの削除とスナップショットの復元は破壊的な操作であり、事前にユーザーから明示的な確認を得る必要があります。 スナップショットの復元は、本番環境を日常的にロールバックするための手段ではありません。
テスト
ユニットテスト/統合テストには、基本的な Postgres(関数なし)を使用します:
import { NetlifyDB } from "@netlify/database-dev"; // npm i -D @netlify/database-dev
import { Client } from "pg";
import { afterAll, beforeAll, expect, test } from "vitest";
let db: NetlifyDB, connectionString: string;
beforeAll(async () => {
db = new NetlifyDB();
connectionString = await db.start();
await db.applyMigrations("./netlify/database/migrations");
});
afterAll(async () => { await db.stop(); });
test("inserts and reads a user", async () => {
const client = new Client({ connectionString });
await client.connect();
await client.query("INSERT INTO users (name) VALUES ($1)", ["Ada"]);
const { rows } = await client.query("SELECT name FROM users");
expect(rows).toEqual([{ name: "Ada" }]);
await client.end();
});
NetlifyDB(options?):directory(ディスクに永続化します。省略するとメモリ内になります)、port(デフォルトはランダム)、logger。
Netlify 環境全体(関数/エッジ関数は本番環境と同様に NETLIFY_DB_URL を読み取ります):
import { NetlifyDev } from "@netlify/dev"; // npm i -D @netlify/dev
const netlifyDev = new NetlifyDev({ projectRoot: "./fixtures/my-project" });
await netlifyDev.start(); // sets NETLIFY_DB_URL in the runtime
// ...tests...
await netlifyDev.stop();
データベースブランチ(デプロイ時)
本番データベースにアクセスするのは本番デプロイのみです。各デプロイプレビューには専用のブランチが作成され、プレビュー作成時点の本番データのコピーがシードされます。そこでのスキーマ/データ変更が本番環境に影響することはありません。自動的に設定されるため、コードの変更は不要です。
プレビューブランチには PII を含む本番データが含まれる場合があります。また、プレビューデプロイのリンクは公開されています。プレビューリンクを共有する前にユーザーに警告してください。
実行時の注意事項
Environment not configured(getDatabase()で接続文字列を解決できない):Netlify の外部、Lambda 互換モードの Functions、または古い CLI で実行しています。対処方法:connectionStringを明示的に渡してください。
Lambda 互換モードは、const db = getDatabase({ connectionString: "postgres://..." });connectionStringを自分で渡す必要がある唯一のプリミティブです。database feature not available for this account— クレジット制プランが必要です。compute customization requires a Pro or higher plan— 自動スケール/スリープ設定には Pro 以上が必要です。Free/Personal ではデフォルト設定が使用されます。branch limit reached: maximum <N> branches...— アクティブなデプロイプレビューごとにブランチを 1 つ消費します。不要なブランチを削除するか、アップグレードしてください。database not found— DB がプロビジョニングされていません。netlify database initを実行してください。cannot reset the production branch— リセットは本番以外でのみ可能です。
制約事項
- プラン: Netlify Database はクレジット制プランでのみ利用できます。アクティブな DB はコンピューティングと帯域幅のクレジットを消費します。ストレージは 2026 年 7 月 1 日まで無料です。
- 権限: データベースを削除できるのは Team Owner のみです。接続文字列を表示できるのは Team Owner と Developer のみです(
Access Deniedはロールの権限不足を意味します)。 - シークレット: 接続文字列にはユーザー名とパスワードが含まれます。絶対にコミットせず、シークレットマネージャー/環境変数プロバイダーに保存してください。
既存の Postgres プロジェクトを Netlify Database に切り替える
3 つのフェーズで進めます。プロビジョニング(ブランチにベースラインスキーマを作成)、リハーサル(コードを切り替え、データをプレビューブランチにコピーして検証)、切り替え(データを本番環境にインポートしてマージ)。任意の Postgres ソース(Neon、Supabase、RDS、セルフマネージド、旧 @netlify/neon)に対応します。pg_dump/pg_restore(ソースと一致するバージョン)を使用します。短時間のデータ損失期間が発生します。最終エクスポート後から本番デプロイまでにソースへ書き込まれたデータは移行されません。
フェーズ 2/3 のコード切り替え(Drizzle):
import { drizzle } from "drizzle-orm/netlify-db";
import * as schema from "./schema";
export const db = drizzle({ schema });
詳細な手順(ダンプのフラグ、ロールバック、クリーンアップ):references/migration-from-extension.md および references/legacy-extension.md。
Netlify の基本ルール(データベース)
これはドキュメントの事実ではなく、組織内の慣例です。ctx-gen によってレンダリングされたスキルに統合され、生成されることはありません。スキルのメンテナーが管理します。
- 本番データの変更は DML マイグレーションとして表現します。エージェントが行を直接編集することはありません(人間向けには UI で行を編集できますが、エージェント向けの操作手段ではありません)。
- プレビュー ブランチには、PII を含む本番データが含まれる場合があります。また、プレビューのデプロイリンクは公開されています。共有する前に警告してください。
- ドキュメントに記載された操作手段のみを使用してください。内部エンドポイントに対する生の psql、
netlify apiによるスクレイピング、ローカルの CLI 設定ファイルからのトークン読み取りは禁止です。 - 詳細ガイドはこのスキルにあります:
references/operational-footguns.md、references/migrations.md、references/local-dev.md、references/cli-commands.md、references/migration-from-extension.md、references/legacy-extension.md。 - スキーマの変更をホスト型データベースに反映できるのは、コミット済みのマイグレーションファイルをデプロイで適用した場合のみです。Netlify がホストするデータベースに対して、いかなる形式でも
drizzle-kit pushを実行してはいけません。また、NETLIFY_DB_URLに対してdrizzle-kit migrateを実行したり、netlify database connectまたは直接接続を介して DDL を適用したりしてはいけません。 netlifyコマンドまたはデプロイが失敗した場合は、正確なエラー、デプロイログの URL、影響を受けるサイト/ブランチをユーザーに提示して停止してください。復旧コマンドを考案したり、より低レベルのツールに移行したりしてはいけません。- 初回デプロイの
createSiteDatabaseで401 Access Deniedが発生した場合:--prodを指定した最初のデプロイで発生したなら、プレビューを先にデプロイして再試行します(netlify deploy、--prodは指定しません)。プレビューでも失敗した場合は、その旨を報告して停止してください。回避策としてapi.netlify.comに curl したり、netlify api createSiteDatabaseを実行したり、ローカルの CLI 設定からトークンを取得したりしてはいけません。 - 既存データの変更依頼は、本番とプレビューブランチのどちらを対象にするのか曖昧です。プロンプトに記載がなければ確認してください。誰かに代わって操作する場合は、本番データに触れないことをデフォルトとします。
- 破壊的なデータベース操作(REST ブランチの削除、スナップショットの復元、あらゆるリセット)には、事前にユーザーの明示的な確認が必要です。本文で、スナップショットの復元を本番環境の通常のロールバック手段として提示してはいけません。
- バージョンを固定してください:
drizzle-ormとdrizzle-kitは@betaからインストールする必要があります。latestにはdrizzle-orm/netlify-dbアダプターがなく、失敗します。本文でこれを単なる推奨事項として弱めてはいけません。