Diagnosing devcontainer performance
Before you start: this module won't produce the same numbers for everyone
The classic devcontainer I/O slowdown — an npm install or a test suite noticeably slower inside the container than outside — is primarily a Docker Desktop (macOS/Windows) or WSL2-with-project-files-on-the-Windows-side phenomenon. A native Linux environment (the container runs directly on the machine's Linux kernel, with no filesystem translation through a VM) typically doesn't reproduce this symptom to the same degree, because the bind mount goes straight to the host filesystem without the translation layer that causes the slowdown elsewhere.
Concretely:
- If you're on Docker Desktop (macOS/Windows) or WSL2 with your project files under
/mnt/c/...: you can reproduce this diagnosis with real numbers — follow the method below as written. - If you're on native Linux: read through the method anyway, but expect your measurements to show no significant difference — that's a valid result, not a failed exercise. Reason about what you would expect to measure in the described environment, and note why yours differs.
The method: measure → hypothesize → test → verify
1. Measure
The reported symptom: npm install (or an equivalent I/O-heavy command — lots of small files) is noticeably slower inside the devcontainer than outside. Quantify it, don't rely on a gut feeling:
# inside the devcontainer
rm -rf node_modules
time npm install
# on the host, outside any container, if the same toolchain is available there
rm -rf node_modules
time npm install
Note both real-world times (real). On Docker Desktop or WSL2-with-files-on-Windows, a multi-fold gap (2x to 10x, per community documentation and field experience — not an officially guaranteed figure from Microsoft) is plausible for a project with many small files (typically node_modules, with tens of thousands of entries).
2. Hypothesize
If your project lives in a folder bind-mounted from the Windows filesystem (/mnt/c/... as seen from WSL, or a C:\Users\... folder mounted into Docker Desktop), the hypothesis to test is: every file access from the container crosses an extra translation layer (the WSL2 bridge to NTFS, or Docker Desktop's file sharing) that adds per-operation latency — negligible for one large file, but that adds up across tens of thousands of small operations like those in an npm install.
3. Test
For WSL2 specifically, Microsoft's official filesystems documentation lays out the fix. It explicitly recommends, for the fastest performance from a Linux command line:
"For the fastest performance speed, store your files in the WSL file system if you are working in a Linux command line (Ubuntu, OpenSUSE, etc)."
And spells out what to avoid:
"Use the Linux file system root directory:
/home/<user name>/Project— Not the Windows file system root directory:/mnt/c/Users/<user name>/Project"
The /mnt/ prefix is the tell: the moment you see it in a path from WSL, you're accessing a mounted drive (the Windows filesystem), not the distro's native Linux filesystem.
Move your project and re-measure:
# clone (or copy) the project into WSL2's native Linux filesystem
cd ~
git clone <your-repo> project-linux-native
cd project-linux-native
rm -rf node_modules
time npm install
If your devcontainer is opened from this new path (~/project-linux-native, not /mnt/c/...), the container's bind mount now points at WSL2's native Linux filesystem, with no /mnt/ traversal.
4. Verify
Compare the three timings: bare host outside any container, container with the project under /mnt/c/..., container with the project on the native Linux filesystem. A successful verification looks like:
- Host, no container: X seconds
- Container, project under
/mnt/c/...: significantly slower than X - Container, project on the Linux filesystem: close to X, noticeably faster than the
/mnt/c/...run
If the third number lands close to the first, your hypothesis is confirmed: the /mnt/ crossing was the dominant factor, not Docker or the devcontainer itself.
If you're on native Linux
Follow the same method, but be aware step 3 doesn't apply the same way: on native Linux there's no equivalent /mnt/ crossing — a Docker bind mount on native Linux accesses the host filesystem directly, through the same system calls any process would use. If you still measure a significant gap between host and container on native Linux, the likely cause is elsewhere: a missing .dockerignore letting the build context balloon, a Docker volume (rather than a bind mount) behaving differently, or a cgroup/resource limit (CPU, memory) placed on the container that indirectly slows down the CPU-bound work of an npm install (dependency resolution). Document that alternative hypothesis and test it the same way — measure, hypothesize, test, verify — rather than concluding "bind mounts are always slow" without evidence specific to your environment.
What this module does NOT guarantee
Don't present a precise figure ("2x slower", "5x slower") as a universal truth — these gaps depend on the Docker Desktop version, the WSL2 configuration, the project's file count, and shift with tool versions (for instance, newer Docker Desktop file-sharing backends narrow this gap compared to older ones). What this module guarantees is the method and the direction of the principle Microsoft documents — not a fixed number to memorize.
What's next
You've now built, mirrored in CI, audited, and tuned a setup for a single repo. The final module asks you to reason through a problem with no established official answer: how to standardize all of this across an entire organization.
Check your understanding
Per Microsoft's official WSL documentation, where should you store project files for the best performance, if you're working from a Linux command line (Ubuntu, etc.) under WSL?
Is a project accessed via /mnt/c/... from WSL, per Microsoft's docs, treated as native access to the Linux file system?
You're working on native Linux (no Docker Desktop, no WSL) and a devcontainer with a bind mount is slow. What does this module say about the odds it's the same issue described here?
Want to hear about the next modules?
The Academy stays free and open-access, no sign-up required. If you'd just like to be notified by email when a new module ships, here you go — no obligation, unsubscribe anytime with one click.