Maintenance

Site is under maintenance — quizzes are still available.

Go to quizzes

Bind mount host directories

Learn to bind mount host directories into Docker containers with practical steps, troubleshooting, and what to study next.

Focus: bind mount host directories into containers

Sponsored

Imagine you've built a web application inside a Docker container. Every time you edit a source file on your host machine, you have to rebuild the image and restart the container just to see the change. That's slow, breaks your flow, and makes development painful. Bind mounts solve this by letting you share a directory from your host machine directly into a container, so changes on your host appear instantly inside the container. No rebuilds, no restarts — just real-time syncing.

The problem this lesson solves

By default, every file a container writes lives in its writable layer — a temporary space that disappears when the container stops. This isolation is great for security but terrible for development. If you want to edit code on your laptop and test it in a container, you'd normally need to:

  1. Make your change on the host.
  2. Rebuild the Docker image (docker build).
  3. Stop and remove the old container (docker rm -f).
  4. Start a new container (docker run).

That cycle takes seconds (or minutes!), breaking concentration and slowing progress. Worse, any data generated inside the container (logs, databases, uploaded files) vanishes on shutdown.

Pro tip: Without bind mounts or volumes, containers are essentially stateless. Bind mounts let you persist and share data without embedding it in the image.

Core concept / mental model

Think of a bind mount as a hole in the container wall. You punch a hole between a path on your host (say ~/my-project) and a path inside the container (say /app). Anything the container writes to /app actually shows up in ~/my-project on your host, and vice versa.

  • Host directory: the source — absolute or relative path on your machine.
  • Container directory: the target — path inside the container.
  • Mount point: the connection happens when you start the container with the --mount or -v flag.

Bind mounts are one of several mount types in Docker, alongside volumes (managed by Docker) and tmpfs mounts (in-memory only). For this lesson, focus on bind mounts: they give you full control because you decide exactly which host directory gets shared.

How it works step by step

When you create a container with a bind mount, Docker does the following:

  1. Reads the host path you specified. If it's a relative path, Docker resolves it from the directory where you run the docker command.
  2. Creates the directory on the host if it doesn't already exist (for --mount, it creates; for -v, it also creates on-the-fly).
  3. Mounts that directory over the container's target path — hiding any existing content in the container at that path.
  4. Keeps the mount alive for the container's lifetime. When the container stops, the mount is removed, but the host directory remains untouched.

Key detail: Bind mounts bypass Docker's storage drivers. They go straight to the host filesystem, meaning performance is native — fast reads/writes — but also that filesystem permissions (UID/GID) apply directly.

Using --mount vs. -v

The modern, explicit syntax uses --mount. The older shorthand is -v.

Aspect --mount -v / --volume
Syntax type=bind,source=/host/path,target=/container/path /host/path:/container/path
Readability More verbose, self-documenting Compact but can be ambiguous
Default directory creation Creates host directory if missing Creates host directory if missing
Preferred for automation Yes — explicit and fails safe Less explicit, but widely used
Supports readonly Yes (readonly) Yes (:ro)

Rule of thumb: Use --mount in scripts and Docker Compose to avoid path-ambiguity gotchas. Use -v for quick one-off commands.

Hands-on walkthrough

Let's say you have a Python script on your host at ~/hello/app.py:

# ~/hello/app.py
import time
while True:
    print("Hello from the container!")
    time.sleep(2)

You can run it inside a Python container using a bind mount:

# Absolute path
docker run --rm -it \
  --mount type=bind,source="$(pwd)/hello",target=/app \
  python:3.10 python /app/app.py

Now edit app.py on your host (e.g., change the message). The container will output the new text within two seconds — no rebuild needed!

Example 2: Bind mount with read-only flag

Sometimes you want the container to see files but not modify them (e.g., configuration secrets in dev):

docker run --rm -it \
  --mount type=bind,source="$(pwd)/config",target=/config,readonly \
  ubuntu bash -c "ls /config"

If the container tries to write inside /config, it fails with:

touch: cannot touch '/config/test.txt': Read-only file system

Example 3: Relative path gotcha

Run this command from your home directory:

# Relative source path — Docker resolves from CWD
docker run --rm -it \
  -v ./hello:/app \
  alpine ls /app

It mounts $(pwd)/hello into the container. If you run from a different directory, you'll get an empty mount (or an error if the directory doesn't exist).

Example 4: Persisting logs to the host

Bind mounts are perfect for collecting logs without losing them:

mkdir -p logs
docker run -d --name log-test \
  --mount type=bind,source="$(pwd)/logs",target=/var/log/myapp \
  busybox sh -c "while true; do echo \"$(date)\" >> /var/log/myapp/app.log; sleep 5; done"

Check ./logs/app.log on your host — it updates live.

Compare options / when to choose what

Use case Best choice Rationale
Active development — edit code on host, test in container Bind mount Real-time sync, no rebuild
Persisting database data across container restarts Docker volume Managed lifecycle, better performance on cloud filesystems
Sharing secrets (e.g., SSL certs) without baking into image Bind mount + readonly Transient and controlled
Multi-container shared data (same data used by web + worker) Docker volume Single mount point, simpler orchestration
Logs or metrics that need to survive container restarts Either — bind mount for simplicity, volume for portability Depends on whether you want to manage files manually

Pro tip: If you ever need to move the data to another machine, Docker volumes are easier to back up and transfer. Bind mounts lock your container to a specific host path.

Troubleshooting & edge cases

❌ Mount appears empty inside container

The container's target path already had files, and the bind mount overwrites that directory. Solution: mount to a dedicated empty path, or copy contents manually before mounting.

❌ Permission denied / Operation not permitted

Bind mounts pass through Linux file permissions. If the container runs as root but the host directory is owned by your user, the container can still write — but files created will have UID/GID of the container user. Fix by setting the container's user to match your host UID:

docker run --user $(id -u):$(id -g) -v "$(pwd)/hello:/app" ...

❌ Bind mount not found when using relative paths

Relative paths in -v are relative to the Docker host, not the container. If you're inside a nested shell or a different working directory, the path may resolve incorrectly. Always use absolute paths with --mount for reliability.

❌ Docker Desktop / WSL2 performance slow

On macOS and Windows (via WSL2), bind mounts through Docker Desktop have a performance penalty for high I/O operations (e.g., npm install). Mitigation: keep source files on the Docker Desktop file share (e.g., /Users on macOS), or use a volume with a native filesystem driver.

What you learned & what's next

You now understand how to bind mount host directories into containers — a critical skill for real-time development, log collection, and configuration management. You learned: - How bind mounts punch a hole between host and container filesystems. - The difference between --mount and -v syntax. - How to make mounts read-only. - Common permission pitfalls and performance notes.

Your mission: Try replacing your next docker build / docker run cycle with a bind mount. Edit a file on your host and verify it updates inside the running container instantly.

Next up, you'll explore Docker volumes — the production-grade persistent storage solution that Docker manages for you, making your data portable across environments.

Practice recap

Try this: run a Python container that reads a greeting from a file on your host. Edit the greeting file on your host while the container is running and watch the output change. Then convert your mount to read-only and attempt to write to it from the container — observe the error. This simple exercise cements the bind mount lifecycle and permission behavior.

Common mistakes

  • Using relative paths without double-checking the working directory — Docker resolves them from the host shell's CWD, which may not be what you expect.
  • Mounting to a non-empty container directory — the bind mount hides existing container files, which can break the application if those files are needed.
  • Forgetting to set read-only when mounting secrets or config files — anyone who compromises the container can modify your host files.
  • Assuming bind mounts persist after container removal — the mount is removed, but the host directory remains untouched (good!).
  • On macOS/Windows, using a host path outside the Docker Desktop shared folders — results in a permission error.

Variations

  1. Use --volume (-v) with :ro suffix for a compact read-only bind mount in quick commands.
  2. Leverage Docker Compose volumes: section with type: bind to declare mounts declaratively in multi-container apps.
  3. For production, switch to Docker volumes managed by Docker to decouple data from host infrastructure.

Real-world use cases

  • Mounting source code from your laptop into a development container for hot-reloading during frontend or backend work.
  • Collecting container logs directly into a host directory for analysis with external log shippers (e.g., Filebeat, Fluentd).
  • Providing SSL certificates or configuration files from a host directory to a container without embedding them in the image.

Key takeaways

  • Bind mounts share a host directory into a container; changes are visible instantly on both sides.
  • Use --mount type=bind,source=...,target=... for explicit, scriptable mounts; use -v for quick interactive commands.
  • Bind mounts overwrite any existing content in the container's target directory — use empty or dedicated paths.
  • File permissions from the host apply inside the container; use --user to match UID/GID when needed.
  • Bind mounts are for development and transient data; Docker volumes are better for production persistence.
  • On Docker Desktop (macOS/Windows), bind mounts may have slower I/O; consider volumes for heavy filesystem workloads.

Sponsored

Sponsored

Discussion

Questions, corrections, and tips help everyone reading this page.

0 comments

Add a comment

Shown publicly with your comment.

Be constructive · max 4,000 characters

No comments yet — start the thread.

Related tutorials, quizzes, and articles for this topic.