effidevFlutter・Cloudflareエッジ・クラウドコスト最適化
日本語

Next.js 15+ Server ActionsをCloudflare OpenNext/Workersにデプロイする際のトラブルシューティングと最適化

Next.js Server Actions on Cloudflare Workers

Next.js 15とServer Actionsは、Reactエコシステムに大きな変化をもたらしました。しかし、これをVercelではなくCloudflare Workersのようなエッジ環境で動かそうとすると、いくつかの技術的な壁にぶつかります。幸いなことに、OpenNextのおかげでNext.jsアプリをCloudflareにデプロイするプロセスははるかに簡単になりました。

この記事では、Next.js 15以上の環境でServer ActionsをCloudflare OpenNext/Workersにデプロイする際に遭遇する可能性のあるトラブルシューティングのポイントと、パフォーマンス最適化の方法を詳しく解説します。

1. OpenNextとCloudflare Workersの構造を理解する

VercelはNode.js環境(または独自のエッジランタイム)を提供しますが、Cloudflare WorkersはV8 Isolateベースの独自のランタイムを使用します。したがって、Node.jsの組み込みモジュール(例:fspathcrypto)に直接依存するコードはエラーを引き起こす可能性があります。

OpenNextは、Next.jsのビルド成果物をCloudflare Workersが理解できる形式に変換(Adapter)します。しかし、Server Actionsの場合、フォームデータをパースしてサーバーで実行された結果を返す過程で、ランタイムの違いによる微妙なバグが発生しやすくなります。

2. Server Actionsデプロイ時によくあるエラーと解決策

2-1. FormData パースエラー (Multipart/form-data)

Server Actionsでファイルアップロードを処理する際、multipart/form-dataのパースエラーがよく発生します。Cloudflare Workersのメモリ制限(128MB)やリクエストサイズ制限(一般的に100MB)に引っかかることがあります。

解決策: 大きなファイルのアップロードは、Server Actionsを通じて直接送信するのではなく、Cloudflare R2のPresigned URLを発行して、クライアントから直接アップロード(Direct Upload)する方式を採用すべきです。

// app/actions.ts
'use server'

import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";

const s3 = new S3Client({
  region: "auto",
  endpoint: process.env.R2_ENDPOINT,
  credentials: {
    accessKeyId: process.env.R2_ACCESS_KEY_ID!,
    secretAccessKey: process.env.R2_SECRET_ACCESS_KEY!,
  },
});

export async function getUploadUrl(filename: string, contentType: string) {
  const command = new PutObjectCommand({
    Bucket: process.env.R2_BUCKET_NAME,
    Key: filename,
    ContentType: contentType,
  });

  // エッジで60秒間有効なURLを生成
  const signedUrl = await getSignedUrl(s3, command, { expiresIn: 60 });
  return signedUrl;
}

2-2. Node.js依存関係エラー (Bcryptなど)

ユーザー認証のためにbcryptのようなNode.jsネイティブバインディングライブラリをServer Actionsで使用すると、Workers環境でクラッシュが発生します。

解決策: Web Crypto APIをサポートするbcryptjs(純粋なJS実装)や@node-rs/argon2のWASMバージョン、cf-workers-hashなどを使用する必要があります。

2-3. データベースコネクションプールの枯渇

Server Actionsはリクエストごとに実行されます。PostgreSQLなどと直接接続(TCP)する場合、コネクションが枯渇する可能性があります。

解決策: Cloudflare Hyperdriveを使用してコネクションプーリングを管理するか、HTTPベースのデータベース(例:Prisma Accelerate、Neon Serverless、Supabase REST)を使用してください。

3. パフォーマンス最適化のヒント

3-1. Edge Runtimeを明示する

Server Actionが特定のルートに紐付いている場合、そのルートが明示的にエッジランタイムを使用するように宣言するとパフォーマンスが向上します。OpenNextはこれをより効率的に処理します。

export const runtime = 'edge';

3-2. Revalidateを活用したキャッシュの無効化

Server Actionsの処理完了後にrevalidatePathrevalidateTagを使用する際、OpenNextのKVベースのキャッシュ動作方式を理解する必要があります。Cloudflare KVは結果整合性(Eventual Consistency)を持つため、更新が最大60秒遅延する可能性があります。

即時的なキャッシュの無効化が必要な場合は、Workers KVの代わりにCloudflare D1や外部Redis(Upstashなど)をNext.jsのCustom Cache Handlerとして設定することを検討してください。

まとめ (Summary)

💡 CloudflareでのServer Actionsのためのコアチェックリスト

  • 大きなファイルはServer Actionsの代わりにR2 Presigned URLを使用してクライアントから直接アップロードする。
  • Node.jsネイティブAPI(fs、C++ Addons)の使用を避け、Web APIや純粋なJSパッケージに置き換える。
  • DB接続時はHyperdriveHTTPベースのServerless DBを活用する。
  • revalidatePathを使用する際は、Cloudflare Cache/KVの結果整合性を認識して設計する。

OpenNextとCloudflare Workersの組み合わせは、Next.jsエコシステムを最も安価かつ最速でグローバルにサービス提供できる素晴らしいインフラです。初期のわずかな設定に注意すれば、強力なServer Actionsの利点をエッジで完全に享受することができます。