Next.js × ORM 実践比較:Prisma / Drizzle / Kysely をDocker上で動かして違いを体感する【後編】

  • prisma
    prisma
  • drizzle
    drizzle
  • nextjs
    nextjs
  • react
    react
  • postgresql
    postgresql
  • typescript
    typescript
2025/03/13に公開

はじめに

前編では、Next.js App Router 環境におけるORM選定の観点として、型安全性、マイグレーション、Edge対応、マネージドDBとの相性などを軸に、Prisma / Drizzle ORM / Kysely の3つのORMを比較しました。

👉 前編はこちら:

https://shinagawa-web.com/blogs/nextjs-app-router-orm-comparison

この記事(後編)では、それぞれのORMを実際に導入・実装して比較していきます。

本記事の方針:実際に動かして体感する

Docker上にPostgreSQLとMySQLの両方を構築

各ORMごとにマイグレーション定義・テーブル作成・API実装までを一通り行う

同じ「ユーザー一覧取得API」をそれぞれのORMで書いて比較

実装のしやすさや運用のクセ、型まわりの手触りを実践ベースで体感

この記事で得られること

  • 「Prismaって便利だけど重いって言われる理由は?」
  • 「Drizzleって最近聞くけど、本当に扱いやすい?」
  • 「Kyselyの型推論って実際どう?」

といった、使ってみなければ分からない実装レベルの違い・思想の違いを、自分の手で試しながら理解できる構成になっています。

対象環境・前提

  • Next.js 14(App Router構成)
  • 各ORMはAPI Route(app/api/users/route.ts)で利用
  • DockerでPostgreSQL / MySQLをローカルに立ち上げて接続
  • フロントUIやSWRなどは扱わず、API層の比較に集中

前提知識として推奨

  • Next.js App Routerの構造に触れたことがある
  • ORMを1つでも使ったことがある(Prismaなど)
  • Dockerの基本的な使い方(docker-compose up できる程度)

それでは、まずは環境構築からはじめていきましょう。
次章では、PostgreSQLとMySQLを同時に扱えるDocker構成を用意し、.envを共通化していきます。

今回実装したコードはこちらのリポジトリに格納してありますので合わせてご参照ください。

https://github.com/shinagawa-web/nextjs-app-router-orm-comparison

環境構築(共通準備)

Next.jsプロジェクトの作成とPostgreSQLとMySQLを扱えるDockerコンテナの起動から始めます。

1. プロジェクト作成(orm-app/ ディレクトリ)

npx create-next-app@latest orm-app \
  --ts \
  --app \
  --tailwind \
  --eslint \
  --src-dir \
  --import-alias "@/*"

Image from Gyazo

プロジェクトが作成できましたら開発モードで起動できることを確認します。

npm run dev

Image from Gyazo

2. docker-compose.ymlの作成

Dockerで以下2つのDBを立ち上げます。

  • PostgreSQL(Prisma / Drizzle向け)
  • MySQL(Kysely向け)
docker-compose.yml
version: '3.9'
services:
  postgres:
    image: postgres:15
    restart: always
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: password
      POSTGRES_DB: appdb
    ports:
      - '5432:5432'
    volumes:
      - pgdata:/var/lib/postgresql/data

  mysql:
    image: mysql:8
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: appdb
      MYSQL_USER: user
      MYSQL_PASSWORD: password
    ports:
      - '3306:3306'
    volumes:
      - mysqldata:/var/lib/mysql

volumes:
  pgdata:
  mysqldata:

yamlファイルを作成したらDockerを起動します。

docker-compose up -d

Dockerコンテナ内で接続確認を行います。

PostgreSQL編

コンテナに接続

docker exec -it <postgresコンテナ名> bash

psqlコマンドで接続

psql -U user -d appdb

Image from Gyazo

MySQL編

コンテナに接続

docker exec -it <mysqlコンテナ名> bash

mysqlコマンドで接続

mysql -u user -p
  • パスワード:password

Image from Gyazo

DB接続用 .env.localの作成

# PostgreSQL for Prisma / Drizzle
POSTGRES_URL=postgresql://user:password@localhost:5432/appdb

# MySQL for Kysely
MYSQL_URL=mysql://user:password@localhost:3306/appdb

ディレクトリ構成の確認

いくつかファイルを作成しましたので念のため現在のディレクトリ構成を記載しておきます。

tree -I node_modules -I .git -I public -I .next --dirsfirst -a
.
├── src
│   └── app
│       ├── favicon.ico
│       ├── globals.css
│       ├── layout.tsx
│       └── page.tsx
├── .env.local
├── .gitignore
├── README.md
├── docker-compose.yml
├── eslint.config.mjs
├── next-env.d.ts
├── next.config.ts
├── package-lock.json
├── package.json
├── postcss.config.mjs
└── tsconfig.json

📁 src/app/

これは Next.js App Router 専用のルーティングディレクトリです。以下のような構成が基本になります:

ファイル・フォルダ 役割
page.tsx トップページ (/) に対応するルートコンポーネント
layout.tsx ページ全体の共通レイアウト(HTML構造や共通スタイルなど)
globals.css 全体で使うグローバルCSS(Tailwind等と併用されやすい)
favicon.ico ブラウザのタブに表示されるアイコン

📄 .env.local

環境変数をローカル開発用に記述するファイル(例:DATABASE_URL=...)。
Gitに含めず、個人ごとの設定を保持する目的で使います。

📄 docker-compose.yml

複数のDockerコンテナ(DBやアプリ)を同時に立ち上げるための設定。
例えば、MySQLやPostgreSQLなどの開発用DBを構成している可能性があります。

📄 eslint.config.mjs

ESLint(静的解析ツール)の設定ファイル(ESM形式)。
コードの品質・構文ルールを統一するために使用されます。

📄 next-env.d.ts

Next.js によって自動生成される型定義ファイル。
TypeScript が next 環境を正しく認識できるようにするための補助。

📄 next.config.ts

Next.js のビルド設定ファイル(TypeScript形式)。
例:画像ドメイン許可、リダイレクト、モジュールエイリアスなどの指定が可能。

📄 package.json & package-lock.json

ファイル 内容
package.json プロジェクトの依存ライブラリ、スクリプト、メタ情報を記述
package-lock.json 実際にインストールされたパッケージのバージョンを固定・記録(再現性の保証)

📄 postcss.config.mjs

PostCSS の設定ファイル。
Tailwind CSS を使っている場合、ここでプラグイン指定を行います。

📄 tsconfig.json

TypeScript のコンパイラ設定。
パスエイリアス(@/ など)や strict モード、モジュール形式などをここで制御します。

Prisma編:マイグレーションと API 実装(PostgreSQL)

このセクションでは、Prisma を使って Next.js App Router 環境におけるユーザーデータの読み取り API を構築します。Docker 上の PostgreSQL に接続し、マイグレーション・データ登録・API 実装・型安全な開発体験までを一通り確認します。

Prisma のセットアップ

依存パッケージのインストールと初期化

npm install prisma @prisma/client
npx prisma init

Image from Gyazo

生成される構成:

prisma/
  └── schema.prisma
.env

接続設定

.env.local.env に以下を記載します。

POSTGRES_URL=postgresql://user:password@localhost:5432/appdb

Prisma スキーマ定義

prisma/schema.prisma を以下のように定義します:

generator client {
  provider = "prisma-client-js"
}

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

model User {
  id    Int    @id @default(autoincrement())
  name  String
  email String @unique
}

マイグレーションの実行

npx prisma migrate dev --name init

Image from Gyazo

テーブルが作成されました。

下記コマンドで確認できます。

npx prisma studio

Image from Gyazo

先ほど指定したカラムが存在していますが、レコードはまだありません。

初期データ投入(seed)

prisma/seed.ts を作成:

const { PrismaClient } = require('@prisma/client')

const prisma = new PrismaClient()

async function main() {
  await prisma.user.createMany({
    data: [
      { name: 'Alice', email: 'alice@example.com' },
      { name: 'Bob', email: 'bob@example.com' },
      { name: 'Charlie', email: 'charlie@example.com' },
    ],
  })

  await prisma.$disconnect()
}

main().catch((e) => {
  console.error(e)
  process.exit(1)
})

実行準備

npm install -D ts-node

実行

npx ts-node prisma/seed.ts

レコードが3件作成されたことが確認できます。

Image from Gyazo

API の実装

src/lib/prisma.ts

import { PrismaClient } from '@prisma/client'

const globalForPrisma = globalThis as unknown as {
  prisma: PrismaClient | undefined
}

export const prisma = globalForPrisma.prisma ?? new PrismaClient()

if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma
  • なぜこのような書き方をしているのか?
    Next.js(特にApp Router)では、開発中にモジュールが ホットリロード(HMR)されるたびに再実行されることがあります。
    そのたびに new PrismaClient() を呼んでしまうと、Prismaの接続数制限(特にPlanetScaleやSupabaseなどのマネージドDB)を超えてしまい、接続エラーになります。
意味と狙い
globalThis の利用 グローバル変数として prisma インスタンスを保持し、使い回せるようにする
globalForPrisma.prisma ?? new PrismaClient() 初回実行時は新しく作り、それ以降は再利用する
if (process.env.NODE_ENV !== 'production') 本番環境では毎回生成しても問題ない(1プロセス前提)ため、グローバル汚染を避ける

このパターンはよく「Singletonパターン(開発環境用)」として使われます。

src/app/api/prisma/users/route.ts

import { prisma } from '@/lib/prisma'

export async function GET() {
  const users = await prisma.user.findMany()
  return Response.json(users)
}

解説

  • app/api/prisma/users/route.ts は Next.js App Router の API ルート
    • このファイルがあることで GET /api/prisma/users というエンドポイントが自動的に生成される
  • prisma.user.findMany() は User モデルの全レコードを取得するメソッド
    • 戻り値は User[] 型(Prismaが自動生成)

Prisma + App Router のAPIの魅力

ポイント 内容
1ファイルで完結 route.ts だけでAPIエンドポイントを完結できる
型安全 prisma.user.findMany() の引数・戻り値に型が付く
再利用性が高い Prisma Clientは使いまわしやすく、複数APIで共有できる
null・undefined防止 Prismaの戻り値は適切なUnion型

確認:

http://localhost:3000/api/prisma/users

先ほど作成したユーザーがレスポンスとしてされていればOKです。

Image from Gyazo

型安全な開発体験の具体例

await prisma.user.findMany()の戻り値の型が明示されています。

Image from Gyazo

// 特定のユーザー取得例
const user = await prisma.user.findUnique({
  where: { id: 1 },
})

// 型エラー例(存在しないフィールドを渡すとエラー)
await prisma.user.findUnique({
  where: { foo: 123 } // ❌ 型エラー
})

エディター上でもfooが存在しないことを確認できます。

Image from Gyazo

データ削除(後片付け)

コンテナに接続し、DBに接続した後に、下記コマンドを実行します。

DROP SCHEMA public CASCADE;
CREATE SCHEMA public;

Image from Gyazo

解説

コマンド 意味
DROP SCHEMA public CASCADE; publicスキーマ(≒全テーブル)を削除
CREATE SCHEMA public; 空のスキーマを再作成

このように Prisma は、型の信頼性と記述の簡潔さを両立しつつ、高速な開発体験を提供してくれます。

次章では、SQLライクで軽量な構文が特徴の Drizzle ORM を使って、同じ処理を実装して比較してみます。

Drizzle ORM編:マイグレーションと API 実装(PostgreSQL)

このセクションでは、Drizzle ORM を使って Next.js App Router 環境におけるユーザーデータの読み取り API を構築します。Prismaと同様に Docker 上の PostgreSQL に接続し、スキーマ定義・マイグレーション・初期データ投入・API 実装までを順に確認していきます。

Drizzle のセットアップ

依存パッケージのインストール

npm install drizzle-orm pg postgres
npm install -D drizzle-kit @types/pg

drizzle-orm: ORM 本体
pg, postgres: PostgreSQL ドライバ
drizzle-kit: CLI ツール(マイグレーション用)

drizzle.config.ts の作成

プロジェクトルートに drizzle.config.ts を作成:

import { defineConfig } from 'drizzle-kit'

export default defineConfig({
  dialect: "postgresql",
  schema: './src/schema/drizzle-schema.ts',
  out: './drizzle',
  dbCredentials: {
    url: process.env.POSTGRES_URL as string,
  },
})
項目 内容
DBの種類 PostgreSQL を使用する
スキーマ定義 TypeScriptファイル(pgTable())で行う
マイグレーション生成先 ./drizzle ディレクトリ
接続情報 POSTGRES_URL 環境変数で指定された接続文字列を使う

3. スキーマ定義

Drizzle ORM では、テーブル定義そのものを TypeScript ファイル上で行います。これにより、スキーマ定義と型情報が一致し、IDE 補完や型チェックによる安心感が得られます。

src/schema/drizzle-schema.ts を作成:

import { pgTable, serial, varchar } from 'drizzle-orm/pg-core'

export const users = pgTable('users', {
  id: serial('id').primaryKey(),
  name: varchar('name', { length: 255 }).notNull(),
  email: varchar('email', { length: 255 }).notNull().unique(),
})

💡 解説:

  • pgTable() は PostgreSQL 用のテーブル定義関数で、1つ目の引数がテーブル名、2つ目がカラム定義のオブジェクトです。
  • serial() は PostgreSQL の SERIAL 型に対応。自動インクリメントする主キーです。
  • varchar() は可変長文字列型。{ length: 255 } のように長さを明示します。
  • .notNull() を付けると NOT NULL 制約を加えます。
  • .unique() を付けるとユニークインデックスが張られます。

Drizzle ではこのように TypeScript の文法でスキーマ定義ができるため、別途 Prisma のような DSL ファイルを定義する必要がなく、スキーマとコードの乖離が起きにくいのが大きな利点です。

マイグレーションの実行

初期化(最初のみ)

npx drizzle-kit generate

Image from Gyazo

DBに適用

npx drizzle-kit push

Image from Gyazo

Drizzle Studioで確認

Prismaと同様にGUIでテーブルを確認できます。

npx drizzle-kit studio  

Image from Gyazo

コンソールに表示されたURLにアクセスするとusersテーブルが作成されていることが確認できます。

Image from Gyazo

初期データ投入(seed)

prisma/seed.ts と同様に、scripts/drizzle-seed.ts を作成:

import { drizzle } from 'drizzle-orm/node-postgres'
import { users } from '@/schema/drizzle-schema'
import { Client } from 'pg'
import 'dotenv/config'

const client = new Client({ connectionString: process.env.POSTGRES_URL })
await client.connect()
const db = drizzle(client)

await db.insert(users).values([
  { name: 'Alice', email: 'alice@example.com' },
  { name: 'Bob', email: 'bob@example.com' },
  { name: 'Charlie', email: 'charlie@example.com' },
])

await client.end()

依存パッケージのインストール

npm i dotenv
npm i -D tsx

実行方法

npx tsx scripts/drizzle-seed.ts

Drizzle Studioでレコードが3件作成されていることを確認します。

Image from Gyazo

API の実装

このセクションでは、Drizzle ORM を使って /api/drizzle/users という API エンドポイントを作成します。Next.js の App Router における API Route の仕組みと、Drizzle のクエリ構築方法を理解する上で重要な実装パートです。

src/lib/drizzle.ts

import { drizzle } from 'drizzle-orm/node-postgres'
import { Client } from 'pg'

const client = new Client({ connectionString: process.env.POSTGRES_URL })
client.connect()

export const db = drizzle(client)
💡 解説:
  • pg パッケージの Client を使って PostgreSQL に接続しています。
  • drizzle(client) によって型安全なクエリビルダーが生成され、db 経由であらゆる操作が可能になります。
  • 接続は一度だけ行い、アプリ内で使いまわす設計です(グローバルキャッシュを導入してもよい)。

src/app/api/drizzle/users/route.ts

import { db } from '@/lib/drizzle'
import { users } from '@/schema/drizzle-schema'

export async function GET() {
  const result = await db.select().from(users)
  return Response.json(result)
}
解説:
  • Next.js App Router では route.ts を配置するだけで API エンドポイントが自動的に生成されます。

    • この場合、/api/drizzle/users が生成されます。
  • db.select().from(users) という記述は Drizzle の SQL DSL(Domain Specific Language)構文で、

    • userspgTable() で定義された型付きテーブル
    • .select() で全カラムを、.from() で対象テーブルを指定
  • Response.json(result) により、取得したデータをそのままJSONで返しています。

  • 戻り値の型は typeof users._.columns に基づいて推論され、型安全性が保たれます。

確認:

http://localhost:3000/api/drizzle/users

3件のレコードがレスポンスに含まれていることが確認できます。

Image from Gyazo

型安全な開発体験の具体例

Prisma同様、db.select().from(users)の戻り値の型が明示されています。

Image from Gyazo

const result = await db.select().from(users).where(eq(users.id, 1))

// 型エラー例:存在しないカラム名を指定するとエラー
await db.select({ foo: users.foo }).from(users) // ❌ コンパイルエラー

Image from Gyazo

データ削除(後片付け)

DROP SCHEMA public CASCADE;
CREATE SCHEMA public;

Drizzle ORM は、SQLライクな構文と静的型付けのバランスがよく、App Router + Edge Runtime を見据えた構成にも適しています。次は Kysely を用いた比較実装に進んでいきます。

Kysely編:App Router × Kysely(MySQL)

このセクションでは、Kysely を使って Next.js App Router 環境におけるユーザーデータの取得APIを構築します。Prisma や Drizzle に比べて "よりSQLライクに" 書ける構文と、型の推論力に定評があるのが特徴です。MySQL(PlanetScale なども視野)を接続先とし、マイグレーション・データ登録・API 実装の流れを確認します。

Kysely のセットアップ

パッケージのインストール

npm i kysely mysql2

型定義ファイルの作成

Kyselyでは、テーブルごとの型を自分で定義して渡す必要があります。

src/types/db.ts
import { Generated } from "kysely"

export interface UserTable {
  id: Generated<number> 
  name: string
  email: string
}

export interface Database {
  users: UserTable
}
  • Generated<T> とは?
    • INSERT 時には省略可能
    • SELECT 時には存在する値として扱われる

Kysely クライアントの初期化

src/lib/kysely.ts
import { Kysely, MysqlDialect } from 'kysely'
import { createPool } from 'mysql2'
import type { Database } from '@/types/db'

const dialect = new MysqlDialect({
  pool: createPool({
    database: 'appdb',
    user: 'user',
    password: 'password',
    host: 'localhost',
    port: 3306,
  })
})

export const db = new Kysely<Database>({ dialect })

マイグレーション(手動で SQL 実行)

Kysely は Prisma や Drizzle のようにマイグレーションの仕組みを持っていますがやや使いにくいです。

https://kysely.dev/docs/migrations

そのため、スキーマの管理は手動で SQL を実行する方法を今回は採用しました。

以下は users テーブルを作成するための SQL です:

CREATE TABLE users (
  id INT AUTO_INCREMENT PRIMARY KEY,
  name VARCHAR(255) NOT NULL,
  email VARCHAR(255) NOT NULL UNIQUE
);

この SQL を実行するには、Docker 上で起動している MySQL コンテナに入って実行するのが一般的です。以下のようにして操作できます:

# コンテナに入る
docker exec -it orm-comparison_mysql_1 bash

# MySQLシェルにログイン
mysql -u user -p
# パスワード: password

# DBを選択
USE appdb;

# 上記の CREATE TABLE 文を実行

Image from Gyazo

この手動マイグレーションはやや手間ですが、その分 SQL による明示的な制御が可能で、PlanetScale のようにスキーマ変更に制約があるサービスとの相性も良好です。

PlanetScaleやDockerのMySQLに入って直接実行するか、初期化スクリプトとして用意します。

初期データ投入(seed)

scripts/kysely-seed.ts
import 'dotenv/config'
import { db } from '@/lib/kysely'

async function main() {
  await db.insertInto('users').values([
    { name: 'Alice', email: 'alice@example.com' },
    { name: 'Bob', email: 'bob@example.com' },
    { name: 'Charlie', email: 'charlie@example.com' },
  ]).execute()

  await db.destroy()
}

main().catch((e) => {
  console.error(e)
  process.exit(1)
}).finally(() => {
  process.exit(0)
})

実行方法:

npx tsx scripts/kysely-seed.ts

APIの実装(初期データ投入後に確認)

初期データの投入が完了したら、次のように API エンドポイントを実装してデータ取得の動作を確認できます。

Next.js App Router では、app/api 以下に配置した route.ts ファイルによって API エンドポイントが自動的に生成されます。この例では、/api/kysely/users が GET リクエストに対応するようになります。

また、Kysely のクエリ構文は SQL の構造に似ており、.selectFrom('users').selectAll()SELECT * FROM users に相当するクエリを構築できます。

src/app/api/kysely/users/route.ts
import { db } from '@/lib/kysely'

export async function GET() {
  const users = await db.selectFrom('users').selectAll().execute()
  return Response.json(users)
}
http://localhost:3000/api/kysely/users

このエンドポイントにアクセスすることで、先ほど seed で投入した Alice, Bob, Charlie のデータが JSON 形式で返ってくるはずです。

Image from Gyazo

idが4〜6になっているのはデータを再作成した影響ですので特に気にする必要はありません。

型安全な開発体験

存在しないテーブルを指定すると警告が表示されます。

Image from Gyazo

const result = await db
  .selectFrom('users')
  .select(['id', 'name'])
  .where('email', '=', 'alice@example.com')
  .execute()
  • テーブル名、カラム名はリテラル文字列ではなく補完・型チェック対象になる
  • selectFrom().select() の時点でカラムの型も推論される
  • 誤字や存在しないカラムを指定するとビルドエラーになる

存在しないカラムを指定してwhere句を作成しても警告が表示されます。

Image from Gyazo

戻り値も認識されておりコード上の扱いも問題ありません。

Image from Gyazo

Kysely は SQL に近い記述で柔軟に書きたい人に最適で、PlanetScale(MySQLベース)との相性も良好です。特に型推論の正確さは非常に高く、スキーマとコードの乖離を最小限に保ちつつ開発できます。

以上で、Prisma / Drizzle / Kysely のそれぞれについて、App Router 環境での使い方と使い心地を確認しました。次回はこれらを踏まえて、どのORMがどのユースケースに合うのかを総括します。

コードの比較まとめ

ORM 実装の書きやすさ マイグレーション 型安全 Edge対応 接続初期化のしやすさ
Prisma
Drizzle
Kysely

おわりに

実装してみて初めて見える「思想の違い」

今回、Prisma・Drizzle・Kysely の3つのORMを Next.js App Router 上で実装・比較してきました。それぞれ一見「似たようなことができる」ように見えて、実際に触ってみると設計思想や開発体験に大きな違いがあることがよく分かります。

たとえば、Prismaは「型安全を軸に据えた包括的なORM体験」、Drizzleは「マイグレーションも含めてTypeScriptで完結する一貫性」、Kyselyは「SQLとの距離を極力保ちながら型の恩恵を得る」アプローチです。

ORMは「どれが優れているか」ではなく「どう使いたいか」で選ぶべき

ここまで比較してきた通り、ORM選定で重要なのは「機能の多さ」や「速度」ではなく、「どんな思想で開発したいか」「チームのスキルセットに合っているか」です。

  • Prisma の抽象化は、複雑なJOINや細かいクエリよりも「開発速度」と「型安全性」を重視したい人に向いています。
  • Drizzle は、シンプルで軽く、かつ TypeScript だけで完結させたいというニーズに強く応えます。
  • Kysely は、SQLとの距離を保ちながらも型を最大限に活かしたいエンジニア向きです。

それぞれのORMが得意な構成/不得意なユースケース

ORM 得意なケース 苦手なケース
Prisma 型安全で高速に開発したいアプリケーション SQLを細かく制御したい/PlanetScale利用時
Drizzle 軽量・直感的・TSベースで構成したいモダン構成 高度なリレーションや抽象化が必要な場合
Kysely SQLとの近さを保ちつつ型の恩恵を最大限に得たい マイグレーションを自動管理したい場合

Next.js App Router の構造は、かつての Pages Router と比べて「APIもコンポーネントも関数単位」で完結する方向に進化しています。その中で、どのORMが自然に組み込めるか、どのように構成するのが開発チームにとって無理がないかを見極めることが、選定のポイントになります。

最終的には、「何を実現したいか」と「どんなコードが書きたいか」に立ち返って選ぶことが、健全な技術選定につながると感じました。

今回実装したコードはこちらのリポジトリに格納してありますので合わせてご参照ください。

https://github.com/shinagawa-web/nextjs-app-router-orm-comparison

Supabase / PlanetScaleで試す際の追加ポイント(接続・制限・設定)

Supabase / PlanetScale で試す際の追加ポイント(接続・制限・設定)
今回の比較ではローカルの Docker 上に立てた DB を対象に検証しましたが、実際のプロジェクトでは Supabase や PlanetScale などのマネージドデータベースを使うケースも多くなってきました。
ここでは、それらのサービス上で ORM を試す際に押さえておきたい接続方法や制限、設定上の注意点を補足します。

Supabase(PostgreSQL)の場合

  • 接続URLの形式
    Supabaseのダッシュボードから Database > Connection Pooling もしくは Connection string を選び、.env.local に以下のように記述します
POSTGRES_URL=postgresql://postgres:your-password@db.xxxx.supabase.co:5432/postgres
  • SSLが必須
    Supabaseの接続はSSLがデフォルトで有効です。ORMによっては、接続オプションに ssl: { rejectUnauthorized: false } を明示する必要があります(Kysely / TypeORM など)。

  • リモート接続の許可
    プロジェクト作成直後は一部IPからの接続が制限されていることがあるため、必要に応じて Supabase 側の設定で「外部接続を許可」するオプションを確認してください。

PlanetScale(MySQL)の場合

  • 接続先は「ブランチ」単位
    PlanetScale では「production」「development」などのブランチ単位で接続URLが異なります。接続用のパスワードも個別に生成する必要があります。

  • DATABASE_URL に直接使えない問題(Prisma)
    PlanetScale は標準の MySQL 機能のうちいくつか(例:外部キー制約、複雑なDDL)をサポートしていません。Prismaで使う際は .env に次のように書き、schema.prisma 側で referentialIntegrity = "prisma" にする必要があります。

DATABASE_URL=mysql://<username>:<password>@<host>/<db>?sslaccept=strict
  • Edge対応ライブラリあり
    PlanetScale は @planetscale/database ライブラリを提供しており、これを使えば Next.js Edge Runtime や Cloudflare Workers など fetch ベースの環境でも MySQL に接続可能です(Prisma / TypeORM は非対応)。

  • マイグレーションの制約
    PlanetScale は「オンラインスキーマ変更」を前提としたワークフロー(GUI/CLI)を採用しており、ORMが直接マイグレーションを流す設計とは相性が悪いことがあります。Drizzle や Kysely のようにマイグレーションを明示的に管理・分離できる構成が好まれます。


このように、Supabase / PlanetScale を本番や検証で使う場合、ORM側の設定だけでなくサービス固有の制約や挙動を正しく理解しておくことが重要です。「ORMが対応しているか」だけではなく、「そのORMがそのDBの制限にどう向き合っているか」に注目することで、よりトラブルの少ない構成選びができるはずです。

Xでシェア
Facebookでシェア
LinkedInでシェア

記事に関するお問い合わせ📝

記事の内容に関するご質問、ご意見などは、下記よりお気軽にお問い合わせください。
ご質問フォームへ

技術支援などお仕事に関するお問い合わせ📄

技術支援やお仕事のご依頼に関するお問い合わせは、下記よりお気軽にお問い合わせください。
お問い合わせフォームへ

関連する技術ブログ

弊社の技術支援サービス

お問い合わせ

経営と現場をつなぐ“共創型”の技術支援。
成果に直結するチーム・技術・プロセスを共に整えます。

お問い合わせ