Bind Mount
Imagine editing your app’s source code and having to rebuild the entire Docker image just to see one line change reflected. Painful, right? Bind mounts solve exactly this — they let you punch a direct hole between a folder on your host machine and a folder inside your container, so both stay perfectly in sync in real time. Let’s see how, and when this actually earns its place in your workflow.
What a Bind Mount Actually Is
A bind mount maps an exact path on your host to a path inside the container. There’s no abstraction layer, no Docker-managed storage area — it’s literally the same files, viewed from two places at once. Change a file on the host, and the container sees it instantly. Change it inside the container, and the host sees it too.
flowchart LR
subgraph Host["Host Machine"]
HP["/home/user/my-app<br/>(actual files)"]
end
subgraph Container["Container"]
CP["/app<br/>(same files, mounted)"]
end
HP <==>|"bind mount<br/>(direct, two-way)"| CP
Real World Scenario: Watching a Host File Change, Live
You don’t need to know any programming language to see a bind mount in action. All we need is one text file and a container that keeps reading it. Follow along exactly — every file and command below is complete, nothing to fill in yourself.
Create a folder and one file inside it:
mkdir bind-mount-demo && cd bind-mount-demo
echo "Hello from the host!" > message.txtNow start a container that bind-mounts just this one file, and keeps printing its contents every 2 seconds, forever:
docker container run -d \
--name bind-demo \
-v "$(pwd)/message.txt":/data/message.txt \
busybox \
sh -c "while true; do cat /data/message.txt; sleep 2; done"Now watch its logs:
docker container logs -f bind-demoYou’ll see Hello from the host! printed every 2 seconds. Leave this running, open message.txt in any text editor, change the text to something else, and save it. Within a couple seconds, the new text starts appearing in the logs — without restarting the container, without rebuilding anything. That’s the entire idea behind a bind mount: the container isn’t reading a copy of your file, it’s reading the exact same file, live, off your host disk.
When you’re done, clean up:
docker container rm -f bind-demoTip
Prefer the newer --mount syntax over -v when you want clarity, since it’s explicit about each option:
docker container run -d \
--name bind-demo \
--mount type=bind,source="$(pwd)/message.txt",target=/data/message.txt \
busybox \
sh -c "while true; do cat /data/message.txt; sleep 2; done"-v is shorter and still widely used, but --mount spells out type, source, and target explicitly — less room for typos to silently do the wrong thing, especially when a missing host path just gets silently auto-created as an empty directory with -v.
Bonus: The Same Idea Behind a Real Web App
The demo above is intentionally bare-bones so the concept stays front and center. But the reason bind mounts are popular in the first place is live-reloading actual web apps during development — so here’s that same idea, fully pre-baked, using Python since it needs nothing installed on your host except Docker itself.
Note
You don’t need to know python to understand the concept of Bind Mount.
Create a new folder with exactly this one file inside it:
mkdir python-bind-demo && cd python-bind-demoSave the following as app.py in that folder — copy it exactly as-is:
from flask import Flask
app = Flask(__name__)
@app.route("/")
def home():
return "Hello from the host! Edit this line and refresh."
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000, debug=True)Now run it in a container, bind-mounting the whole folder:
docker container run -d \
--name flask-demo \
-p 5000:5000 \
-v "$(pwd)":/app \
-w /app \
python:3.12-slim \
sh -c "pip install flask && python app.py"Give it a few seconds to install Flask, then open http://localhost:5000 in your browser. You’ll see the message from app.py. Now, without touching the container at all, open app.py, change the text inside the return statement to anything else, and save the file. Refresh the browser — the new text shows up immediately. That’s debug=True restarting the app process the moment it detects the file changed, and it’s only able to see that change because the bind mount is putting your live edits directly in front of it.
Clean up when you’re done:
docker container rm -f flask-demoThis is the single most common real-world use case for bind mounts: local development environments where fast iteration matters more than portability.
Why Bind Mounts Are Rarely the Default Choice
For all their convenience in local dev, bind mounts come with real downsides that make them a poor fit for most production scenarios:
- Host-path dependency. The mount only works if that exact path exists on the host. Move your container to a different machine, a CI runner, or a Kubernetes node, and the path might not exist — breaking portability entirely.
- No Docker-level management. Unlike volumes, Docker doesn’t track, back up, or help you manage bind mounts. You’re fully responsible for the host directory’s lifecycle.
- Permission headaches. Files created inside the container use the container’s UID/GID, which may not match your host user — leading to files you can’t edit or delete without
sudo. - Security exposure. A bind mount gives the container direct read/write access to a real part of your host filesystem. If that container is compromised, so is whatever it’s mounted into.
When to Reach for a Bind Mount
Given those trade-offs, bind mounts make sense in a narrow set of situations:
- Local development, for live code reload without rebuilding images
- Injecting configuration files from the host into a container at a known, fixed location
- Debugging — quickly exposing a container’s internal files to host tools without extracting anything
- CI pipelines that need to share a workspace directory between build steps
Outside of these, you’ll want Docker volumes instead — which we will learn after next chapter.
Don’t Skip The Next
Bind Mount has permission issues. If you have completed the second python example too, you can see that __pycache__ folder remains in your directory even if container is tear down. Yes you want that as part of docker persistence but if you try to remove it:
rm -rf __pycache__You get permission error:
rm: cannot remove '__pycache__/app.cpython-312.pyc': Permission deniedThat’s a classic Bind Mount problem with permissions we will see next.