🧍‍♀️

Next.js StandaloneビルドでPrismaマイグレーションとSeed実行

に公開

Next.jsのビルドについて

npm run build (next build) で実行する Next.jsのビルドには3種類あります。

  • デフォルト : 特別なことはしない
  • export : 静的ファイルとして出力、主にSPAとして利用
  • standalone : 必要なファイル(ライブラリ含む)を抽出する

これらのオプションは next.config.ts(js) で指定できます。

import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  output: "standalone"
};

export default nextConfig;

ServerComponentで動的処理をするなどフルスタックにNext.jsを利用する場合は、基本的に無指定のデフォルトかStandaloneビルドになります。機能的にはどちらも違いはありません。大きな違いはビルド後のファイルサイズです。

Standaloneビルドは、Next.js実行に必要なファイルを自動でトレースをし、そのファイルだけ抽出してビルドをしてくれます。つまりDev環境では必要だが本番環境には不要なライブラリやコードなどが全部消えます。結果的に、ビルド後のファイルサイズが削減されます。

ファイルサイズが削減されて嬉しいのは、Docker利用時にDockerイメージサイズが小さくなることです。イメージサイズが小さいと、push/pullなどの通信量が減るためデプロイ時間や費用が削減可能です。

アプリケーションの構成よって異なりますが、目安としてDockerイメージサイズ(非圧縮時)の違いです。

  • デフォルト : 約800MB
  • Standalone : 約200MB

これを大きいと見るか、大差ないと見るかは状況次第ですが、小さくできるなら小さくしたいというのが人情です。ただ、Standaloneビルドは不要と判断されたファイルは消えてしまい、これが原因で特定の処理が実行できないことがあります。その代表例がPrismaのマイグレーションやSeed実行です。

ということで前置きが長くなりましたが、この記事ではNext.jsをStandaloneビルドした時に、ORM PrismaでマイグレーションやSeedの実行ができるようにする方法を紹介します。

対応方法

まずは普通にStandaloneビルド

Standaloneビルドをするには前述したように next.config.ts(js) ファイルの output 項目を変更します。

import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  output: "standalone"
};

export default nextConfig;

この状態で npm run build もしくは next build をすると .next/standalone ディレクトリにファイルが生成されます。この中の server.js をNode.jsで実行するとNext.jsが起動します。

Dockerfile

Standaloneビルドに対応したDockerfileを作ります。と言っても公式のDocker Exampleがあるので、それをそのまま利用します。マルチステージビルドされているのでサイズも小さくなります。

ExampleではAlpineが指定されていますが、Alpineである必要はなく、Debian系にしたい方は適宜変更をしてください。最終的なDockerイメージサイズもそこまで小さくなるわけじゃないです。

Prismaマイグレーション実行できるようにする

Prismaのマイグレーション実行コマンド npx prisma migrate deploy を実行するためには /prisma ディレクトリが必要です。単純にこれをCOPYするだけで大丈夫です。

Dockerfile
 COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
 COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
 
+# migrate実行時に必要なのでPrisma関係のファイルもコピーする
+COPY --from=builder --chown=nextjs:nodejs /app/prisma ./prisma
+
 USER nextjs

なお、Standaloneビルドだとprismaコマンド自体もインストールされないため、npx prisma を実行した際に自動でインストールされるようになります。

Prisma Seed実行できるようにする

Prisma Seed実行も上記のように単純にCOPYするだけで済ませられるケースもあるのですが、アプリケーションの開発が進むにつれて、Seed実行に必要なファイルが増えていった時に手動で管理するのが非現実的になります。

そこで、Seed実行に必要なスクリプトをVercelがOSSとして公開しているビルドツール vercel/ncc を使います。

非常にシンプルなビルドツールで、依存関係を解決したうえで単一のNode.js実行可能なスクリプトに変換してくれます。僕はnccがシンプルで好きなので使っていますが、他にesbuildなどのビルドツールを使っても大丈夫だと思います。

Dockerfile
@@ -32,6 +32,10 @@
 # Next.jsビルド前にPrismaの型情報を生成する
 RUN npx prisma generate
 
+# seed実行が可能なスクリプトをnccでビルドする
+RUN npx ncc build ./prisma/seed.ts -o seed && \
+    mv seed/client/* seed
+
 RUN \
   if [ -f yarn.lock ]; then yarn run build; \
   elif [ -f package-lock.json ]; then npm run build; \

@@ -59,6 +67,8 @@
 
 # migrate実行時に必要なのでPrisma関係のファイルもコピーする
 COPY --from=builder --chown=nextjs:nodejs /app/prisma ./prisma
+# seed実行ファイルもコピーする
+COPY --from=builder --chown=nextjs:nodejs /app/seed ./seed
 
 USER nextjs

Seed実行コマンドは通常 npx prisma db seed ですが、このDockerコンテナでは node seed/index.js とビルドしたスクリプトを直接実行するようにしています。

以上で、PrismaマイグレーションとSeed実行が可能なNext.js StandaloneビルドのDockerfileができました。完成品のGitHubリポジトリを公開しているのですべてのスクリプトはこちらで確認してください。

ムーザルちゃんねる

Discussion