skip to content

questions

4

Why do developers bind-mount source into a running Docker container instead of rebuilding the image on every edit?

level: juniorimportance: must knowfreq 76%

answer

  1. The image is not the only file source
  2. A host directory stands in for that path
  3. One file, two paths, no copying
  4. Edits land instantly; nothing restarts by itself
  5. Rebuild only when a Dockerfile input changes

basics

~20 s

A bind mount maps a host directory onto a path inside the running container, so an edit on the host is visible to the process instantly. Source baked in with COPY changes only when you rebuild the image.

solid answer

~50 s

`COPY . /app` puts a *snapshot* of the source into an image layer, so changing one file invalidates that layer and every layer after it: you rebuild, recreate the container and wait for the app to start again. A bind mount (`docker run -v "$PWD":/app myapp:dev`) instead maps the host's working copy onto `/app` in the container's mount namespace — no copy, no rebuild, and writes flow both ways. The image still supplies everything else: the runtime, OS packages, the dependencies its build installed, and `WORKDIR`/`ENV`/`USER`/`ENTRYPOINT`. That is why a dev container is usually built from a stage that still carries the toolchain rather than the slim stage that ships. Two limits matter: the mount **hides** whatever the image had at `/app`, and it does not restart or recompile anything — the app's own watcher has to do that.

code

bash · 2 lines
bash
docker build --target dev -t myapp:dev .
docker run --rm -it -p 8080:8080 -v "$PWD":/app myapp:dev

go deeper

for a junior

Be ready to say plainly what a bind mount is: a host directory made to appear at a path inside the running container, set up when the container is created. Know that it removes the build step from the edit cycle, not the restart.

for a middle

Explain the mechanics: why touching one file invalidates a COPY layer and everything after it, why the mount shadows rather than deletes image content, and which parts of the environment still come from the image rather than the host.

for a senior

Show the judgement about where the technique stops — dependency and Dockerfile changes still need a build, generated output written into the mount leaves artefacts on the host, and the shipping image must be exercised before merge rather than only the mounted dev container.

for a principal

Own the standard: one Dockerfile with a dev target and a ship target, the mount declared only in the local stack, and a rule that the artefact promoted to production is always the built image. Be able to argue why fast local loops must not leak into the deployment path.

## What the inner dev loop is The *inner loop* is the cycle you repeat dozens of times an hour: change a line, see the effect. Anything that adds seconds to it is paid for hundreds of times a day, so the whole technique described here exists to keep a source edit off the image-build path. ## Why rebuilding on every edit is expensive A Dockerfile that ends with `COPY . /app` writes a snapshot of your source into an image layer. The build cache keys each instruction on its inputs, so touching a single file changes the checksum of that `COPY`, invalidates it, and invalidates **every instruction after it** — typically the dependency install, the compile step and the final metadata. You then have to recreate the container, because a container is created from a fixed image ID and cannot be pointed at a new one; `docker restart` restarts the *same* container from the *same* image and will happily run your old code. On top of the build you pay the application's own start-up cost every time. ## What a bind mount actually does A bind mount is a kernel mount that makes one directory appear at a second path. Docker sets it up inside the container's mount namespace when the container is created: ```bash docker run --rm -p 8080:8080 -v "$PWD":/app myapp:dev ``` There is no copying and no synchronisation loop. The process inside the container opens `/app/Program.cs` and the kernel resolves it to the same file your editor has open on the host. A write from either side is seen immediately by the other, because on a native Linux engine there is only one file. Bind mounts are read-write unless you ask for `:ro`. The mount is a property of the **container**, not of the image. The image on disk is untouched; the files the image has at `/app` are not deleted, they are *shadowed* for as long as the mount exists. Start the same image without the mount and the baked-in copy is back — which is exactly why the image, not the dev container, remains the deliverable. ## What still comes from the image Everything that is not the mounted directory: the language runtime or interpreter, OS packages, certificates, the dependencies the build installed, and the configuration instructions — `WORKDIR`, `ENV`, `USER`, `EXPOSE`, `ENTRYPOINT`/`CMD`. This is the reason a dev container is normally built from a stage that keeps the toolchain (a build target that still has the compiler, the test runner and the dev dependencies) rather than the slim final stage that ships to production, which may have no shell, no package manager and no compiler at all. ## What a bind mount does *not* do Three things trip people up, and interviewers ask about all three. 1. **It does not restart the process.** The container's PID 1 is still the process you started. A saved file changes bytes on disk; something has to notice. For an interpreted app that is a watcher (the framework's own reload mode); for a compiled app it is a rebuild-and-restart tool. Without one, you are editing files that nobody re-reads. 2. **It does not install anything.** Adding a dependency to `package.json`, `requirements.txt` or a `.csproj` changes an input to a step the *Dockerfile* runs. That is still a rebuild — or at least a command run inside the container — no matter how the source got in. 3. **It hides image content at the mount point.** If the image installed dependencies into a directory that now sits under your mounted tree, the container sees the host's version of that directory instead, which may be empty or built for the wrong OS. The usual repair is a second, deeper mount over just that subdirectory. ## Ownership and the host side Files the container creates under the mount land on the host owned by the UID the container process runs as. A container running as root writing build output into a bind-mounted tree leaves root-owned files in your working copy; running the dev container as your own UID, or keeping generated output off the mounted path, avoids the cleanup. ## Where the technique stops A bind mount is a development affordance. In production the running code must come from the image so that what was tested is what runs; mounting source over a production container's application directory means the image is no longer the artefact and the deployment is no longer reproducible. Keep the mount in the dev command or the local stack file, and never in the shipping one.

  • The container is running with the source bind-mounted, you edit a file, and the response is unchanged. What is the first thing you check?
    Whether anything is watching. A bind mount only changes bytes on disk; the process keeps serving whatever it loaded at start-up. Confirm the app was started in a reload mode (or under a watch tool), then confirm the file you edited is actually inside the mounted path — editing a file the mount does not cover changes nothing inside the container.
  • Does `docker restart` pick up code changes if the source is baked into the image with COPY?
    No. `docker restart` stops and starts the *same* container, which was created from a specific image ID, so it re-runs the old baked-in code. You have to `docker build` a new image and create a new container from it. Only a bind mount, or a rebuild plus recreate, gets new source into a running workload.
  • Why not just bind-mount source in production too, so deploys are instant?
    Because the image stops being the artefact. What was tested in CI is the image; if the running code comes from a directory on the host, the deployment depends on that host's state, is not reproducible, and cannot be rolled back by pinning a tag or digest. Instant deploys are not worth losing the immutability the image was built for.

Baking the source into the image is photocopying a document into a sealed binder; bind-mounting is cutting a window in the binder so the reader sees the page still on your desk, with your latest edits on it.

saying these in an interview costs you the question

  • Says a bind mount rebuilds or updates the image
  • Thinks host edits reach the container with no mount at all
  • Believes the shadowed image files are deleted
  • Expects the process to reload without any watcher
  • Thinks docker restart picks up newly edited source
  • Proposes bind-mounting application source in production

context

open as a page

In a Docker dev container, why does a bind mount over /app hide node_modules, and how do you fix it?

level: middleimportance: must knowfreq 66%

basics

~20 s

The bind mount replaces the whole /app directory, so the node_modules the image installed at build time is shadowed by the host's copy, which is often missing. Fix it with a deeper mount: an anonymous volume at /app/node_modules, seeded from the image.

open as a page

Why does bind-mounting source into a Docker container not reload a compiled service such as a .NET app?

level: middleimportance: should knowfreq 45%

basics

~20 s

The container runs a compiled artefact produced at build time, and a bind mount only changes source on disk. Nothing recompiles it: a runtime-only image has no compiler and nothing is watching. You need a dev stage with the SDK plus a watch process.

open as a page

Why does a file watcher inside a Docker container miss host edits made over a bind mount?

level: seniorimportance: nice to knowfreq 33%

basics

~20 s

Watchers rely on kernel inotify events. On a native Linux engine the bind mount is the same filesystem, so events arrive; when the directory reaches the container through a VM's file-sharing layer, host-side changes are often never raised as events. Polling is the fallback.

open as a page