Skip to Content
DocsDockerData & NetworkingVolumes & Bind Mounts

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:

Terminal
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.txt

You will see hello printed. Now remove the container and start a fresh one from the same image:

Terminal
docker rm -f proof-container docker run -d --name proof-container-2 nginx docker exec proof-container-2 cat /tmp/note.txt

This 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 MountNamed Volume
Storage locationA folder you choose, on your machineA folder Docker manages for you
You can browse it directlyYes — it is a real folder on your computerNot easily — it lives inside Docker’s own storage area
Typical useLocal development — editing source code liveData 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:

Terminal
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 at localhost:3000.
  • -v "$(pwd)":/app — the bind mount. $(pwd) is your current folder on your computer; /app is where it appears inside the container. Changes on either side now show up on both.
  • -v /app/node_modules — keeps node_modules separate 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

  1. Run your Next.js app with the bind-mount command above.
  2. Confirm localhost:3000 loads.
  3. Edit some visible text in a page component, save, and confirm it updates without restarting the container.
  4. 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_modules volume line?

Next → Container Networking

docker volumes vs bind mounts, docker nextjs live reload, docker node_modules volume, docker dev container

Last updated on