Skip to main content

Command Palette

Search for a command to run...

Docker on Windows: The Good, the Bad, and WSL 2

Understanding Docker’s Windows reality with WSL 2

Updated
5 min read
Docker on Windows: The Good, the Bad, and WSL 2
N
Senior-level Fullstack Web Developer with 10+ years experience, including 2 years of Team Lead position. Specializing in responsive design and full-stack web development across the Vue.js and .NET ecosystems. Skilled in Azure/AWS cloud infrastructure, focused on DevOps techniques such as CI/CD. Experienced in system design, especially with software architecture patterns such as microservices, BFF (backend-for-frontend). Hands-on with Agile practices in team leading, and AI-assisted coding.

Series: Containers, Actually: Building Real Local Dev Environments
ACT II — Docker on Windows
Previous: Core Docker Concepts Without the Mysticism
Next: WSL 2 as a First-Class Development Environment

Docker documentation often reads as if Windows were an afterthought. Instructions assume Linux semantics, filesystem behavior, and process models that simply don’t exist on Windows. When things go wrong, Windows users are left with vague advice: “try WSL”, “restart Docker”, “don’t mount your drive”.

This article exists to explain why those suggestions exist—and why they actually make sense once you understand the machinery underneath.

Docker on Windows is not broken. It’s layered. And once you see the layers clearly, the friction starts to disappear.


Why Windows Is “Special” in Docker Land

Docker was born in a Linux world.

Its core features—namespaces, cgroups, overlay filesystems—are Linux kernel primitives. On Linux, Docker runs containers natively. On Windows, that isn’t possible in the same way. Windows has a different kernel, a different filesystem model, and different process isolation semantics.

That means Docker on Windows has always needed translation.

Early Docker for Windows solved this by hiding Linux inside virtual machines. Over time, that approach improved—but it also created confusion, performance issues, and a sense that Docker was “heavy” or unpredictable.

Understanding Docker on Windows requires understanding how Linux is provided.


The Early Days: Hyper-V and the “Big VM” Era

Before WSL 2, Docker Desktop relied on Hyper-V, Microsoft’s hypervisor.

The model looked like this:

  • A full Linux virtual machine runs in Hyper-V

  • Docker daemon runs inside that VM

  • Windows talks to Docker through a bridge

This worked—but poorly for developers.

Problems included:

  • Slow filesystem access

  • High memory usage

  • Awkward networking

  • Poor tooling integration

  • Constant context-switching between Windows and Linux worlds

The VM felt opaque. Developers knew it existed, but couldn’t comfortably live inside it.

Hyper-V wasn’t the wrong tool. It just wasn’t the right experience.


Enter WSL 2: A Different Kind of Virtualization

WSL 2 changed everything.

Instead of emulating Linux behavior, WSL 2 runs a real Linux kernel inside a lightweight VM, deeply integrated into Windows.

This matters.

WSL 2:

  • Uses an actual Linux kernel

  • Supports native Linux system calls

  • Uses ext4 internally

  • Shares networking seamlessly with Windows

  • Integrates with Windows processes and tools

From Docker’s perspective, WSL 2 isn’t a workaround—it’s a Linux host.

That’s why Docker Desktop eventually switched to WSL 2 as its primary backend.


Why WSL 2 Is Effectively Linux (Not “Linux-Like”)

WSL 2 isn’t a compatibility layer. It’s Linux running under virtualization.

Inside WSL 2:

  • /proc behaves like Linux

  • File permissions behave like Linux

  • Inotify works

  • Performance characteristics match Linux far more closely than Windows

For container workloads, this is the critical distinction. Docker expects Linux behavior. WSL 2 provides it.

Once your code and containers live inside WSL 2, Docker stops behaving “weird” and starts behaving normally.


Filesystems: Where Most Pain Comes From

Most Docker-on-Windows frustration traces back to filesystem behavior.

Windows uses NTFS.
Linux uses ext4.

They are optimized for different workloads and make different guarantees. When Docker containers access files on NTFS through translation layers, performance suffers—especially for workloads with:

  • Many small files

  • Frequent file watching

  • Heavy I/O (Node, PHP, Composer, npm, yarn)

This is not a Docker bug. It’s a physics problem.


NTFS vs ext4: The Performance Reality

NTFS:

  • Excellent for Windows workloads

  • Strong metadata guarantees

  • Slower for Linux-style access patterns

  • Expensive permission translation

ext4:

  • Designed for Linux tools

  • Fast metadata operations

  • Predictable behavior for containers

  • Native permission handling

When you mount C:\project into a Linux container, every filesystem operation crosses boundaries:
Windows → WSL → Linux → container

That’s a lot of friction.

When your code lives inside WSL’s ext4 filesystem, those boundaries vanish.


Why Code Should Live Inside WSL

This is the single most important rule for Docker on Windows.

Your source code should live inside the WSL filesystem, not under C:\.

That means:

  • /home/youruser/project

  • Not /mnt/c/Users/...

Benefits:

  • Massive performance improvements

  • Reliable file watching

  • Fewer permission issues

  • Predictable container behavior

Windows tools can still access these files via \\wsl$, and VS Code can edit them directly using Remote WSL. You don’t lose convenience—you gain stability.


Why Mounting from C:\ Hurts Performance

Bind mounts from Windows paths introduce:

  • Filesystem translation overhead

  • Permission mapping

  • Event notification delays

  • Inconsistent behavior across tools

For small scripts, it might feel “fine”. For real applications, it quietly degrades everything.

The rule of thumb:

If your app feels slow in Docker on Windows, check where your code lives.

Nine times out of ten, it’s the filesystem.


What Docker Desktop Actually Does Behind the Scenes

Docker Desktop on Windows is not “Docker with a UI”. It’s an orchestrator.

Behind the scenes, it:

  • Sets up a WSL 2 Linux environment

  • Runs the Docker daemon inside it

  • Bridges networking between Windows and Linux

  • Manages volumes and images

  • Exposes a friendly interface for control

When you run Docker commands from Windows or WSL, you’re talking to the same daemon. The difference is where your files live and how they’re accessed.

Understanding this removes a lot of superstition.


Cooperating With the System, Not Fighting It

Once you accept these realities, Docker on Windows becomes straightforward:

  • Use WSL 2

  • Keep code inside the Linux filesystem

  • Let Docker run where it belongs

  • Use Windows for editing and orchestration, not execution

Windows stops being “the problem” and becomes what it’s good at: a host, a UI, and a coordinator.


What This Enables Next

Now that Docker on Windows makes sense structurally, we can talk about tooling and workflow—how VS Code, terminals, package managers, and automation fit together without friction.

In the next article, we’ll assemble a practical, Windows-friendly toolchain for containerized development that holds up under daily use—not just tutorials.

Docker on Windows isn’t about compromise anymore.
It’s about alignment.

Containers, Actually: Building Real Local Dev Environments

Part 14 of 18

This series explores full-stack local development with Docker—from core concepts and best practices to a real Windows implementation. The goal is to understand how things run, why they work, and how to build reproducible production environment.

Up next

Core Docker Concepts Without the Mysticism

Building clear mental models for Docker systems