mcpField
N
netlify-database

netlify-database

github.com/netlifyデータ・データベース473.0k 回インストール6 日前に更新
リポジトリ

netlify-database について

Netlify プロジェクトでマネージド Postgres を使うためのスキルです。クエリ、マイグレーション、Drizzle 連携、ローカル開発、データベース CLI の手順を説明します。

主な機能

  1. 01マネージド Postgres のセットアップ
  2. 02パラメーター化 SQL クエリ
  3. 03マイグレーションの生成とデプロイ
  4. 04Drizzle ORM アダプターの案内
  5. 05ローカルデータベースと CLI の手順

活用シーン

  1. 01Netlify プロジェクトへの Postgres 導入
  2. 02Functions やビルドからのデータ照会
  3. 03マイグレーションによるスキーマ変更管理
  4. 04ローカルデータベースを使った開発とテスト

インストール

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

$npx skills add https://github.com/netlify/context-and-tools --skill netlify-database

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

同梱ファイル

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

references/
cli-commands.md
legacy-extension.md
local-dev.md
migration-from-extension.md
migrations.md
operational-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
connectSQL 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}/databaseDB を作成します(既存の接続文字列がある場合はそれを返します)。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 を明示的に渡してください。
    const db = getDatabase({ connectionString: "postgres://..." });
    
    Lambda 互換モードは、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 によってレンダリングされたスキルに統合され、生成されることはありません。スキルのメンテナーが管理します。

  1. 本番データの変更は DML マイグレーションとして表現します。エージェントが行を直接編集することはありません(人間向けには UI で行を編集できますが、エージェント向けの操作手段ではありません)。
  2. プレビュー ブランチには、PII を含む本番データが含まれる場合があります。また、プレビューのデプロイリンクは公開されています。共有する前に警告してください。
  3. ドキュメントに記載された操作手段のみを使用してください。内部エンドポイントに対する生の psql、netlify api によるスクレイピング、ローカルの CLI 設定ファイルからのトークン読み取りは禁止です。
  4. 詳細ガイドはこのスキルにあります:references/operational-footguns.md、references/migrations.md、references/local-dev.md、references/cli-commands.md、references/migration-from-extension.md、references/legacy-extension.md。
  5. スキーマの変更をホスト型データベースに反映できるのは、コミット済みのマイグレーションファイルをデプロイで適用した場合のみです。Netlify がホストするデータベースに対して、いかなる形式でも drizzle-kit push を実行してはいけません。また、NETLIFY_DB_URL に対して drizzle-kit migrate を実行したり、netlify database connect または直接接続を介して DDL を適用したりしてはいけません。
  6. netlify コマンドまたはデプロイが失敗した場合は、正確なエラー、デプロイログの URL、影響を受けるサイト/ブランチをユーザーに提示して停止してください。復旧コマンドを考案したり、より低レベルのツールに移行したりしてはいけません。
  7. 初回デプロイの createSiteDatabase で 401 Access Denied が発生した場合:--prod を指定した最初のデプロイで発生したなら、プレビューを先にデプロイして再試行します(netlify deploy、--prod は指定しません)。プレビューでも失敗した場合は、その旨を報告して停止してください。回避策として api.netlify.com に curl したり、netlify api createSiteDatabase を実行したり、ローカルの CLI 設定からトークンを取得したりしてはいけません。
  8. 既存データの変更依頼は、本番とプレビューブランチのどちらを対象にするのか曖昧です。プロンプトに記載がなければ確認してください。誰かに代わって操作する場合は、本番データに触れないことをデフォルトとします。
  9. 破壊的なデータベース操作(REST ブランチの削除、スナップショットの復元、あらゆるリセット)には、事前にユーザーの明示的な確認が必要です。本文で、スナップショットの復元を本番環境の通常のロールバック手段として提示してはいけません。
  10. バージョンを固定してください:drizzle-orm と drizzle-kit は @beta からインストールする必要があります。latest には drizzle-orm/netlify-db アダプターがなく、失敗します。本文でこれを単なる推奨事項として弱めてはいけません。

コメント