Volumes & Bind Mounts
Every container gets its own temporary storage. Remove the container, and that storage — along with anything you changed inside it — is gone. This page shows the two ways Docker solves that.
Proving the Problem
Run a plain container and create a file inside it:
docker run -d --name proof-container nginx
docker exec proof-container sh -c "echo hello > /tmp/note.txt"
docker exec proof-container cat /tmp/note.txtYou will see hello printed. Now remove the container and start a fresh one from the same image:
docker rm -f proof-container
docker run -d --name proof-container-2 nginx
docker exec proof-container-2 cat /tmp/note.txtThis fails — note.txt does not exist. The file only ever lived inside the first container’s own temporary storage, which was deleted along with it.
Two Ways to Keep Data Alive
Docker offers two mechanisms that both work by connecting a container to storage that survives outside of it. They differ in where that storage lives.
| Bind Mount | Named Volume | |
|---|---|---|
| Storage location | A folder you choose, on your machine | A folder Docker manages for you |
| You can browse it directly | Yes — it is a real folder on your computer | Not easily — it lives inside Docker’s own storage area |
| Typical use | Local development — editing source code live | Data that only the container needs, like a database’s files |
You will use named volumes properly once a database enters the picture in the next section. For a Next.js app on its own, a bind mount solves the more immediate problem: editing code and seeing changes without rebuilding the image every time.
Bind Mount: A Live-Reloading Dev Container
An image is a fixed snapshot of your code. Once you build it, the code inside it does not change. So if you edit a line of code, the running container does not see that edit — it is still running the old, baked-in copy. To see the change, you would normally have to build a new image and start a new container from it. That gets slow if you are editing code all day.
A bind mount avoids this. Mounting means connecting a folder on your computer directly to a folder inside the container, so both point to the same files. There is no copying involved. When you save a file on your computer, the container sees that exact change immediately, because it is reading the same file — not a copy of it.
Instead of rebuilding your image every time you change a line of code, you can mount your project folder straight into a container and run the Next.js dev server inside it.
Run with a bind mount
From your project folder:
docker run -d -p 3000:3000 \
-v "$(pwd)":/app \
-v /app/node_modules \
-w /app \
--name next-dev \
node:20-alpine \
sh -c "npm install && npm run dev"-p 3000:3000— connects port 3000 on your computer to port 3000 inside the container, so you can open the app atlocalhost:3000.-v "$(pwd)":/app— the bind mount.$(pwd)is your current folder on your computer;/appis where it appears inside the container. Changes on either side now show up on both.-v /app/node_modules— keepsnode_modulesseparate from the bind mount above. Explained below.
$(pwd) works in Git Bash, macOS, and Linux terminals. On Windows PowerShell, use ${PWD} instead. On Command Prompt, use %cd%.
-w /app— sets the working folder for the command that runs next.sh -c "npm install && npm run dev"— installs dependencies and starts the Next.js dev server, both inside the container.
Confirm live reload works
Open http://localhost:3000 . Now edit a page in your code editor, on your actual computer, and save it. The browser should update, exactly like running npm run dev outside Docker.
Why node_modules Needs Its Own Line
Some npm packages contain code built for one specific operating system. A node_modules folder installed on Windows or macOS will not work inside the Linux container.
-v /app/node_modules keeps node_modules separate. It does not use your project’s node_modules folder. Instead, the container makes its own copy — one built for Linux. Docker calls this an anonymous volume.
Skipping the second line is one of the most common Docker + Node.js mistakes. The container ends up with a node_modules built for the wrong operating system, and breaks. Always keep this line, even though it looks redundant.
Hands-on Task
- Run your Next.js app with the bind-mount command above.
- Confirm
localhost:3000loads. - Edit some visible text in a page component, save, and confirm it updates without restarting the container.
- Stop and remove the container, then run it again — confirm your code changes are still there (because they live on your computer, not inside the container).
Quick Check
- Can you explain, in your own words, why a removed container loses its data?
- Do you know when to reach for a bind mount versus a named volume?
- Can you explain what would go wrong without the separate
node_modulesvolume line?
Next → Container Networking