Using Docker may seem like overkill for a local Next.js project, and indeed, perhaps it is. However there as some unique requirements to get hot reloading working in a Docker development environment which are worthy of note. I hope this configuration will be useful either in isolation, or when integrating a Next.js app into a larger service architecture.
Prerequisites:
Step 1. Create a Dockerfile
In the root of your Next.js project, create your Dockerfile. See the inline comments for a description of each step:
# Dockerfile
# Use node alpine as it's a small node image
FROM node:alpine
# Create the directory on the node image
# where our Next.js app will live
RUN mkdir -p /app
# Set /app as the working directory
WORKDIR /app
# Copy package.json and package-lock.json
# to the /app working directory
COPY package*.json /app
# Install dependencies in /app
RUN yarn install
# Copy the rest of our Next.js folder into /app
COPY . /app
# Ensure port 3000 is accessible to our system
EXPOSE 3000
# Run yarn dev, as we would via the command line
CMD ["yarn", "dev"]
Step 2. Create docker-compose.yml
Again in the root of your Next.js project, create docker-compose.yml
:
# docker-compose.yml
version: "3"
services:
web:
build:
context: .
dockerfile: Dockerfile
container_name: web
restart: always
volumes:
- ./:/app
- /app/node_modules
- /app/.next
ports:
- 3000:3000
This is a very simple compose file, as we only have one service. The key point is the volumes
attribute. By referencing the root of our app (./:/app
), our node modules folder (/app/node_modules
), and Next.js (/app/.next
) we ensure our Next.js app can 'see' the changes we make through our Docker image, and therefore trigger hot reloading when we change a file.
Step 3. Update next.config.js
The final change for hot reloading is to add webpack middleware so we poll for changes. Update your next.config.js
file to include the following:
// next.config.js
module.exports = {
webpackDevMiddleware: config => {
config.watchOptions = {
poll: 1000,
aggregateTimeout: 300,
}
return config
},
...
}
Step 4. Build your image
Now you're ready to build your Docker image! Run compose with the --build
switch and in a minute or so you should have a fresh node image running your Next.js app in all it's containerised glory (thanks to Docker's caching mechanisms, subsequent builds are a lot faster).
$ docker-compose up -d --build
Fire up [localhost:3000](http://localhost:3000)
in your browser, and any changes you make will be instantly reflected. No need to docker-compose down / up
every time. Pretty sweet.
References
Many thanks to these posts whose authors pointed me in the right direction: