Vercelが提供するEdge Functionsは、世界中のエッジノードで実行されるサーバーレス関数で、低レイテンシーを実現しつつグローバルなデプロイが可能です。
しかし、Edge環境でデータベースにアクセスする際には、いくつかの制約や注意点があります。今回は、VercelのEdge FunctionsでPrismaを使ってSupabaseのPostgreSQLデータベースに接続する方法と注意点をまとめました。
Edge Functionsの特徴と制限
Edge Functionsは標準のサーバーレス関数と比較して以下のような特徴があります:
- V8 isolatesで実行される(Node.jsの全機能は使えない)
- 起動が高速
- コールドスタートの影響が小さい
- メモリ制限がある
- 実行時間の制限がある
このような特性により、通常のNode.js環境で動作するPrismaクライアントをそのまま使うことができません。
Prisma Edge Clientのセットアップ
1. 必要なパッケージのインストール
1
2
|
npm install @prisma/client
npm install -D prisma
|
2. schema.prismaの設定
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
// schema.prisma
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
directUrl = env("DIRECT_URL") // マイグレーション用
}
generator client {
provider = "prisma-client-js"
}
// モデル定義
model User {
id String @id @default(uuid())
email String @unique
name String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
|
3. 環境変数の設定
.env
ファイルや、Vercelのダッシュボードで以下の環境変数を設定します:
1
2
3
4
5
|
# PgBouncerを使用したプール接続(アプリケーションクエリ用)
DATABASE_URL="postgresql://postgres.[project-ref]:[password]@[project-ref].pooler.supabase.co:6543/postgres"
# 直接接続(マイグレーション用)
DIRECT_URL="postgresql://postgres:[password]@db.[project-ref].supabase.co:5432/postgres"
|
Edge Functions向けのPrismaクライアント実装
Next.jsのApp Routerを使う場合
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
// lib/prisma.ts
import { PrismaClient } from '@prisma/client/edge'
const prismaClientSingleton = () => {
return new PrismaClient()
}
declare global {
var prisma: undefined | ReturnType<typeof prismaClientSingleton>
}
const prisma = globalThis.prisma ?? prismaClientSingleton()
export default prisma
if (process.env.NODE_ENV !== 'production') globalThis.prisma = prisma
|
Route Handlerの実装例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
// app/api/users/route.ts
import { NextResponse } from 'next/server'
import prisma from '@/lib/prisma'
export const runtime = 'edge' // これが重要!
export async function GET() {
try {
const users = await prisma.user.findMany()
return NextResponse.json({ users })
} catch (error) {
console.error('Error fetching users:', error)
return NextResponse.json(
{ error: 'Failed to fetch users' },
{ status: 500 }
)
}
}
|
注意点とベストプラクティス
1. PgBouncerの活用
SupabaseはPgBouncerによる接続プーリングを提供しています。Edge Functionsのような短命なサーバーレス環境では、接続プーリングが非常に重要です:
- 接続数の制限を回避
- コールドスタートの影響を軽減
- 接続オーバーヘッドを削減
2. トランザクション実行時の注意点
Edge環境では実行時間に制限があるため、長時間実行される複雑なトランザクションはタイムアウトするリスクがあります。シンプルで短時間で完了するトランザクションなら問題なく動作しますが、複雑で時間のかかるトランザクションは標準のサーバーレス関数に移行することを検討しましょう。
3. マイグレーション処理
マイグレーションは必ずDIRECT_URL
を使って実行する必要があります:
マイグレーションコマンドはPgBouncerを経由しないので、必ず直接接続が必要です。
4. 接続エラーのハンドリング
Edge環境では接続エラーが発生する可能性が高いため、適切なエラーハンドリングを実装しましょう:
1
2
3
4
5
6
7
8
9
10
11
12
|
try {
// データベース操作
} catch (error) {
if (error instanceof Prisma.PrismaClientInitializationError) {
// 接続エラーの処理
console.error('Database connection failed:', error)
} else {
// その他のエラー処理
console.error('Operation failed:', error)
}
// エラーレスポンスの返却
}
|
5. リソース制限の考慮
Edge Functionsには実行時間とメモリに制限があります。大量のデータを取得する場合はページネーションを検討するか、バックグラウンドジョブとして標準のサーバーレス関数に移行することも検討しましょう。
Next.jsとの統合
Next.jsのApp Routerを使用する場合、Server Componentsから直接Prismaを呼び出すことができます:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
// app/users/page.tsx
import prisma from '@/lib/prisma'
export const runtime = 'edge'
export default async function UsersPage() {
const users = await prisma.user.findMany()
return (
<div>
<h1>Users</h1>
<ul>
{users.map(user => (
<li key={user.id}>{user.name} ({user.email})</li>
))}
</ul>
</div>
)
}
|
まとめ
VercelのEdge FunctionsでPrismaを使ってSupabaseのデータベースにアクセスするには:
- Prisma Edge Clientを使用する
- PgBouncerを通じた接続プーリングを活用する
- マイグレーションには
DIRECT_URL
を使用する
- エラーハンドリングを適切に実装する
- リソース制限を考慮した設計を行う
適切に設定すれば、VercelのEdge FunctionsとPrisma、Supabaseを組み合わせることで、グローバルに低レイテンシーなアプリケーションを実現できます。特に単純なCRUD操作や読み取りが多い場合には、優れたパフォーマンスを発揮します。