Next.jsをDockerで開発するときのハマりポイントとその解決法について
これは何?
ローカルで動かしていたNext.jsの開発環境をDockerに移した。
いくつかハマったので、解決法を備忘録として残す。
ローカルで動かしていた環境
- Next.js 15.2.3
- Postgres 16
- bun 1.1.34
- Prisma 6.3.1
Dockerに移行した結果の環境構成
- Next.js 15.3.1
- Docker Compose 2.32.4
- Postgres 16
- bun 1.1.34
- Prisma 6.3.1
Dockerで動かすためにNext.jsを15.3.1
にアップグレードした。
Dockerfileの構築
ハマりポイント
next build
に失敗。tsconfig.json
のパスエイリアスをdocker
で解決できず、↓を参考にwebpackのconfigを設定するも、失敗。
解決法
Next.jsではTurbopackのbuildが15.3からサポートされていたため、↓を参考に2025/04時点の最新版の15.3.1にアップグレードしてnext build --turbopack
で解決。Turbopackはtsconfig.json
に定義されているpaths
の設定を読み取り、自動的に解決することができるためである。
Turbopackは2025/04時点ではプロダクションビルドにまだ対応してないが、開発環境で使うなら問題なしと判断。
最終的なDockerfileは以下のとおり。
FROM oven/bun:latest
# create user
ARG username=vscode
ARG useruid=1001
ARG usergid=${useruid}
RUN groupadd --gid ${usergid} ${username} \
&& useradd -s /bin/bash --uid ${useruid} --gid ${usergid} -m ${username} \
#
# and add sudoers for install library post docker operation
&& apt-get update \
&& apt-get install -y sudo \
&& echo ${username} ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/${username} \
&& chmod 0440 /etc/sudoers.d/${username} \
#
# for prisma
&& apt-get install -y openssl
USER ${username}
WORKDIR /app
# for bun
COPY package.json ./
COPY bun.lockb ./
RUN bun install
# copies rest of application code
COPY . .
RUN bunx prisma generate
RUN bun deployable-test
useradd
はdev container
を使う想定で行ったが、最終的に使わなかった。が、まったく無駄な設定というわけではないので残した。
最終行のRUN bun deployable-test
がpackage.json
のscripts
で指定したビルドコマンドにあたる。
{
"private": true,
"scripts": {
"build": "prisma generate && next build",
"dev": "next dev --turbopack",
"start": "next start",
"test": "vitest",
"lint": "next lint",
"deployable-test": "next build --turbopack"
},
# ... 省略
実はnext dev --turbopack
でパスエイリアスの解決自体は可能なため、開発環境で動かす分にはNext.jsではビルドコマンドの実行は不要だと後でわかった。とはいえ、Dockerのビルドの段階でエラーが出てくれたほうが不具合調査が捗るので残している。しかし時間がかかる処理なので、不要と判明したら削除する。
ちなみにDockerで動かすにあたりstandalone
モードにしてイメージサイズの縮小を図ったが、プロダクションビルドにDockerを使わないのであまり意味がないかもしれない。
import {withSentryConfig} from '@sentry/nextjs';
/** @type {import('next').NextConfig} */
const nextConfig = {
output:'standalone',
}
docker-compose構築
ローカルでの開発と同じように、ローカルのソースを変更したら開発サーバをホットリロードさせる構成としたかった。以下に課題を示す。
ハマりポイント
ローカルのソースを変更してもホットリロードされない。
当初はdev container
を使い、ワークスペースディレクトリとバインドマウントさせてローカルソースと同期させることで解決させようとした。しかしうまく動かなかったのと、dev container
のメモリ消費量とパソコンのバッテリー消費量が以外と多く、断念した。
次に↓を参考にWATCHPACK_POLLING=true
を有効にしてnext dev
した。しかしこれもうまくいかなかった。そもそもコンテナ上にコピーしたソースコードを編集しないとホットリロードされないので、いちいちコンテナに入って開発するのは辛いと感じた。
解決法
↓を参考にDocker compose
のwatch
モードを利用することにした。このモードでホットリロードに対応しているフレームワークを動かすと、dockerでホットリロードを実現できる。
.dockerignore
に指定すれば監視の対象外にできるため、更新の多そうな以下のファイルをwatchの対象外にした。
node_modules
npm-debug.log
Dockerfile*
docker-compose*
.dockerignore
.git
.gitignore
README.md
LICENSE
.vscode
.next
*.swp
/scripts
また、package.json
が編集されたらイメージを再ビルドする設定とした。
最終的なファイルは以下の通り:
volumes:
pg-data:
services:
postgres:
container_name: postgres
image: postgres:16.4-alpine3.20
volumes:
- pg-data:/var/lib/postgresql/data
- type: bind
source: "./dump"
target: "/dump"
ports:
- "5432:5432"
environment:
- POSTGRES_DATABASE=postgres
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=password
- POSTGRES_ROOT_PASSWORD=root
healthcheck:
test: pg_isready -U postgres -d postgres
interval: 3s
timeout: 3s
retries: 5
app:
build:
context: '.'
dockerfile: Dockerfile
ports:
- "3000:3000"
command: >
sh -c "bun dev"
user: vscode
develop:
watch:
- action: sync
path: .
target: /app
- action: rebuild
path: ./package.json
depends_on:
postgres:
condition: service_healthy
target: /app
の/app
は、Dockerfile
で指定したWORKDIR
の /app
と同じ。
.env
ファイルの指定はしていない(next dev
で自動的に読み込んでくれるため)。
以下のbun dev
は、package.json
のscripts
で指定したnext dev --turbopack
が実行されるよう指定している。
command: >
sh -c "bun dev"
この状態で↓のコマンドでコンテナを起動し、ローカルのソースコードを編集するとホットリロードされた。
docker compose up --watch
dev container
で開発する手もないわけではないが、バインドマウントの指定が意図通りにいかない可能性が高く、かつ消費メモリも多く、これまでVSCodeで利用していた拡張機能を一から入れなおさないといけないのが辛さを感じた。
まとめ
これまでローカルで開発してきた体験をなるべく崩さず、かつ、開発環境のスピードも落とさずに開発するにはどうしたらよいか考えた結果、上記の設定となった。
そもそも、なぜ開発環境をDocker化したかというと、↓の記事のようにCIを動かしやすくするためだ。e2eをDocker環境で構築しておけば、github actions
で特殊な設定を多用せずともCI
を動かせると想定している。
この記事が誰かの参考になればうれしいです。
Discussion