Windows Subsystem for Linux 2 (WSL2) has fundamentally changed how developers work on Windows. Instead of dual-booting, running heavy virtual machines, or struggling with compatibility layers, you can now run a full Linux environment natively alongside Windows with near-bare-metal performance. Whether you write Node.js, Python, Go, Rust, or any other language, WSL2 gives you genuine Linux tooling without leaving your Windows desktop.
This guide walks you through everything you need to set up a professional-grade Linux development environment on Windows using WSL2. We will cover installation, Ubuntu configuration, Windows Terminal setup, Docker integration, VS Code Remote development, file system best practices, networking, GPU support, and managing multiple distributions.
Prerequisites
Before you begin, make sure you have:
- Windows 10 version 2004 (build 19041) or later, or Windows 11
- At least 8 GB of RAM (16 GB recommended for Docker workloads)
- Virtualization enabled in your BIOS/UEFI (Intel VT-x or AMD-V)
- An internet connection to download distributions
- PowerShell or Windows Terminal with Administrator privileges
Note: If you are running Windows 10, make sure all Windows Updates are installed. Older builds may have partial WSL2 support with known bugs. Windows 11 provides the best WSL2 experience, including systemd support and native GUI application rendering.
What Is WSL2?
WSL2 (Windows Subsystem for Linux version 2) is a compatibility layer built into Windows that allows you to run Linux binary executables natively. Unlike WSL1, which translated Linux system calls into Windows NT kernel calls, WSL2 runs a real Linux kernel inside a lightweight Hyper-V virtual machine.
Key characteristics of WSL2:
- Real Linux kernel: WSL2 ships with a Microsoft-maintained Linux kernel (based on kernel 5.15+ as of 2025) that receives regular updates through Windows Update.
- Full system call compatibility: Because it runs a genuine kernel, WSL2 supports tools like Docker, systemd, FUSE file systems, and eBPF that WSL1 could not handle.
- Lightweight: The virtual machine starts in about one second and consumes minimal resources when idle.
- Tight Windows integration: You can call Windows executables from Linux, access Windows files from Linux (and vice versa), and use
localhostnetworking between the two systems.
# Check your current WSL version
wsl --version
WSL1 vs WSL2
Understanding the differences helps you choose the right version for your workflow:
| Feature | WSL1 | WSL2 |
|---|---|---|
| Architecture | Translation layer | Lightweight VM with real kernel |
| Linux kernel | None (syscall translation) | Full Linux kernel |
| File system performance (Linux files) | Moderate | Native ext4 speed |
| File system performance (Windows files) | Fast (direct NTFS access) | Slower (9P protocol) |
| System call compatibility | Partial (~70%) | Full (100%) |
| Docker support | No | Yes |
| systemd support | No | Yes (Windows 11) |
| Memory usage | Lower | Dynamic (grows/shrinks) |
| Boot time | Instant | ~1 second |
| Networking | Shares Windows network stack | Virtual ethernet adapter |
For most developers, WSL2 is the correct choice. The only scenario where WSL1 might be preferable is when you must heavily access files stored on the Windows NTFS partition, since WSL1 has faster cross-OS file access.
Installing WSL2 and Ubuntu
Microsoft has simplified the installation process significantly. On modern Windows builds, a single command handles everything:
Simplified installation (recommended)
Open PowerShell as Administrator and run:
wsl --install
This command enables the required Windows features (Virtual Machine Platform and Windows Subsystem for Linux), downloads the latest WSL2 Linux kernel, sets WSL2 as the default, and installs Ubuntu.
Restart your computer when prompted:
# After restart, Ubuntu will launch automatically for first-time setup
# You will be prompted to create a UNIX username and password
Manual installation (older Windows builds)
If wsl --install is not available, enable the features manually:
# Enable WSL feature
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
# Enable Virtual Machine Platform
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
# Restart your computer, then set WSL2 as default
wsl --set-default-version 2
Install a specific distribution
You can choose from several distributions:
# List all available distributions
wsl --list --online
# Install a specific distribution
wsl --install -d Ubuntu-24.04
# Other popular options:
# wsl --install -d Debian
# wsl --install -d openSUSE-Tumbleweed
# wsl --install -d kali-linux
Initial Ubuntu Configuration
After your Ubuntu distribution launches for the first time and you create your user account, run these essential configuration steps:
Update the system
sudo apt update && sudo apt upgrade -y
Install essential development tools
sudo apt install -y build-essential git curl wget unzip zip \
software-properties-common apt-transport-https \
ca-certificates gnupg lsb-release
Configure Git
git config --global user.name "Your Name"
git config --global user.email "your.email@example.com"
git config --global init.defaultBranch main
git config --global core.autocrlf input
Important: Setting
core.autocrlftoinputensures that Git converts Windows-style line endings (CRLF) to Unix-style (LF) on commit but leaves LF endings untouched on checkout. This prevents line-ending issues when sharing code between Windows and Linux tools.
Generate SSH keys
ssh-keygen -t ed25519 -C "your.email@example.com"
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
# Display the public key to add to GitHub/GitLab
cat ~/.ssh/id_ed25519.pub
Set up a better shell prompt (optional)
Many developers prefer Zsh with Oh My Zsh for a more productive terminal experience:
sudo apt install -y zsh
sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
Windows Terminal Setup
Windows Terminal is the recommended terminal application for WSL2. It supports multiple tabs, split panes, GPU-accelerated text rendering, and deep customization.
Installation
Install Windows Terminal from the Microsoft Store or via winget:
winget install --id Microsoft.WindowsTerminal -e
Configure Ubuntu as the default profile
Open Windows Terminal Settings (Ctrl+,) and set your Ubuntu profile as the default. In the settings.json file, you can also customize the appearance:
{
"defaultProfile": "{YOUR-UBUNTU-GUID}",
"profiles": {
"list": [
{
"name": "Ubuntu",
"source": "Windows.Terminal.Wsl",
"startingDirectory": "//wsl$/Ubuntu/home/yourusername",
"fontFace": "CascadiaCode NF",
"fontSize": 11,
"colorScheme": "One Half Dark",
"cursorShape": "filledBox"
}
]
}
}
Useful keyboard shortcuts
| Shortcut | Action |
|---|---|
Ctrl+Shift+T | New tab |
Ctrl+Shift+D | Duplicate pane |
Alt+Shift+D | Split pane |
Ctrl+Tab | Switch tabs |
Ctrl+Shift+W | Close pane |
File System Best Practices
Understanding file system performance in WSL2 is critical for a productive workflow. This is one of the most common sources of confusion and frustration for new WSL2 users.
The golden rule
Store your project files inside the Linux file system, not on the Windows drive.
# FAST: Files in your Linux home directory
# Path: ~/projects/my-app
# Actual location: ext4 file system inside WSL2 VM
cd ~/projects/my-app
time git status # ~0.1 seconds
# SLOW: Files on the Windows drive accessed from WSL2
# Path: /mnt/c/Users/yourname/projects/my-app
# Crosses the 9P protocol bridge on every file operation
cd /mnt/c/Users/yourname/projects/my-app
time git status # ~2-5 seconds (10-50x slower)
Why the performance difference exists
WSL2 runs inside a lightweight VM with its own ext4 file system. Accessing files on the Windows NTFS partition requires crossing the VM boundary using the 9P protocol, which adds latency to every file operation. For a node_modules folder with thousands of small files, this overhead becomes dramatic.
Accessing files across boundaries
Even though you should store projects on the Linux side, you can still access files from both systems:
# From WSL2, access Windows files
ls /mnt/c/Users/yourname/Documents
# From Windows Explorer, access Linux files
# Type this in the Explorer address bar:
# \\wsl$\Ubuntu\home\yourusername\projects
# From PowerShell, access Linux files
explorer.exe \\wsl$\Ubuntu\home\yourusername
Recommended directory structure
mkdir -p ~/projects ~/tools ~/scripts
# Keep all development work under ~/projects
# Keep downloaded tools under ~/tools
# Keep automation scripts under ~/scripts
Docker Desktop Integration with WSL2
Docker Desktop for Windows uses WSL2 as its backend, providing native Linux container performance without the overhead of a traditional Hyper-V VM.
Installation
- Download and install Docker Desktop for Windows.
- During installation, ensure “Use WSL 2 instead of Hyper-V” is selected.
- After installation, open Docker Desktop Settings and navigate to Resources > WSL Integration.
- Enable integration with your Ubuntu distribution.
Verify the installation
From your WSL2 Ubuntu terminal:
docker --version
docker compose version
docker run hello-world
Resource management
Docker Desktop with WSL2 can consume significant memory. Configure limits in ~/.wslconfig on the Windows side:
# Create/edit C:\Users\yourname\.wslconfig
[wsl2]
memory=8GB
processors=4
swap=2GB
After modifying .wslconfig, restart WSL2:
wsl --shutdown
Running containers
Since Docker runs inside the WSL2 VM, you get full Linux container performance:
# Run an Nginx container
docker run -d -p 8080:80 --name webserver nginx
# Access it from both WSL2 and Windows browser at http://localhost:8080
# Run a development database
docker run -d -p 5432:5432 \
-e POSTGRES_PASSWORD=devpassword \
--name devdb postgres:16
# Use Docker Compose for multi-container setups
docker compose up -d
For a complete Docker installation guide on Ubuntu, see our article on How to Install Docker on Ubuntu.
VS Code Remote - WSL Extension
Visual Studio Code’s Remote - WSL extension lets you use VS Code on Windows while running all tools, terminals, and extensions inside WSL2. This is the recommended way to edit code stored on the Linux file system.
Setup
- Install Visual Studio Code on Windows (not inside WSL2).
- Install the WSL extension (identifier:
ms-vscode-remote.remote-wsl). - Open a WSL2 terminal and navigate to your project directory.
- Launch VS Code from the terminal:
cd ~/projects/my-app
code .
VS Code will install its server component inside WSL2 automatically and connect to it. You will see “WSL: Ubuntu” in the bottom-left corner of VS Code, confirming you are running in remote mode.
Key benefits
- Extensions run inside WSL2: Language servers, linters, debuggers, and formatters execute in the Linux environment, eliminating cross-OS compatibility issues.
- Terminal is a real Linux shell: The integrated terminal is your WSL2 bash/zsh, not PowerShell.
- File watching works natively: Hot-reload for frameworks like React, Vue, and Next.js works without additional configuration because the file watcher operates on the Linux file system.
- Git integration uses Linux Git: VS Code uses the Git binary inside WSL2, avoiding line-ending and path issues.
Recommended extensions for WSL2 development
Install these extensions inside the WSL2 environment (they will appear under “WSL: Ubuntu - Installed”):
# From inside WSL2 terminal
code --install-extension dbaeumer.vscode-eslint
code --install-extension esbenp.prettier-vscode
code --install-extension ms-python.python
code --install-extension golang.go
code --install-extension bradlc.vscode-tailwindcss
Networking Between Windows and WSL2
WSL2 networking has evolved significantly. On modern Windows 11 builds with WSL2 2.0+, networking uses mirrored mode by default, which simplifies most connectivity scenarios.
Accessing WSL2 services from Windows
By default, services running inside WSL2 are accessible from Windows via localhost:
# Start a development server in WSL2
python3 -m http.server 3000
# Access it from Windows browser: http://localhost:3000
Accessing Windows services from WSL2
You can reach Windows services from WSL2 using localhost as well (mirrored mode on Windows 11), or use the Windows host IP:
# Find the Windows host IP (useful for older builds)
cat /etc/resolv.conf | grep nameserver
# Output example: nameserver 172.28.80.1
# Or use the hostname
ping "$(hostname).local"
Configure mirrored networking (Windows 11)
Add to your .wslconfig file on Windows:
# C:\Users\yourname\.wslconfig
[wsl2]
networkingMode=mirrored
dnsTunneling=true
autoProxy=true
Port forwarding for external access
If you need external devices to reach services running in WSL2:
# Forward port 3000 from Windows to WSL2 (run as Administrator)
netsh interface portproxy add v4tov4 listenport=3000 listenaddress=0.0.0.0 connectport=3000 connectaddress=localhost
# Remove the forwarding rule when no longer needed
netsh interface portproxy delete v4tov4 listenport=3000 listenaddress=0.0.0.0
# List all forwarding rules
netsh interface portproxy show v4tov4
GPU and CUDA Support
WSL2 supports GPU passthrough, allowing you to run CUDA workloads, machine learning frameworks, and even graphical Linux applications directly.
Prerequisites
- An NVIDIA GPU with a recent Windows driver (Game Ready or Studio driver 470.76+)
- Windows 11 or Windows 10 build 21H2+
Verify GPU access
# Check if the GPU is visible
nvidia-smi
# You should see your GPU model, driver version, and CUDA version
Install CUDA Toolkit inside WSL2
# Do NOT install a Linux NVIDIA driver inside WSL2 -- use the Windows driver
# Only install the CUDA toolkit
wget https://developer.download.nvidia.com/compute/cuda/repos/wsl-ubuntu/x86_64/cuda-keyring_1.1-1_all.deb
sudo dpkg -i cuda-keyring_1.1-1_all.deb
sudo apt update
sudo apt install -y cuda-toolkit
Test with PyTorch
pip install torch torchvision
python3 -c "import torch; print(f'CUDA available: {torch.cuda.is_available()}'); print(f'Device: {torch.cuda.get_device_name(0)}')"
Important: Never install a Linux NVIDIA display driver inside WSL2. The Windows GPU driver handles the GPU passthrough. Installing a Linux driver will cause conflicts.
Managing Multiple Distributions
WSL2 allows you to run multiple Linux distributions simultaneously, which is useful for testing across different environments or isolating workloads.
Install additional distributions
# List available distributions
wsl --list --online
# Install additional distributions
wsl --install -d Debian
wsl --install -d Ubuntu-22.04
Switch between distributions
# List installed distributions and their status
wsl --list --verbose
# Launch a specific distribution
wsl -d Debian
# Set a default distribution
wsl --set-default Ubuntu-24.04
Export and import distributions
This is useful for creating backups or sharing pre-configured environments with your team:
# Export a distribution to a tar file
wsl --export Ubuntu-24.04 D:\backups\ubuntu-24.04-backup.tar
# Import a distribution from a tar file
wsl --import MyCustomUbuntu D:\wsl\MyCustomUbuntu D:\backups\ubuntu-24.04-backup.tar
# Launch the imported distribution
wsl -d MyCustomUbuntu
Remove a distribution
# Unregister and delete a distribution (WARNING: destroys all data)
wsl --unregister Debian
WSL Commands Reference
Here is a comprehensive reference table of the most important WSL commands:
| Command | Description |
|---|---|
wsl --install | Install WSL with default Ubuntu distribution |
wsl --install -d <distro> | Install a specific distribution |
wsl --list --online | List all available distributions |
wsl --list --verbose | List installed distributions with version and state |
wsl --set-default-version 2 | Set WSL2 as default for new installations |
wsl --set-default <distro> | Set the default distribution |
wsl --set-version <distro> 2 | Convert a WSL1 distribution to WSL2 |
wsl --shutdown | Shut down all running distributions and the VM |
wsl --terminate <distro> | Terminate a specific distribution |
wsl --export <distro> <file> | Export a distribution to a tar file |
wsl --import <name> <path> <file> | Import a distribution from a tar file |
wsl --unregister <distro> | Remove a distribution and delete all its data |
wsl --update | Update the WSL2 Linux kernel |
wsl --version | Display WSL version, kernel version, and WSLg version |
wsl --status | Show WSL configuration and default distribution |
wsl -d <distro> -u root | Launch a distribution as root user |
wsl hostname -I | Display the IP address of the WSL2 VM |
Troubleshooting
WSL2 fails to start with a virtualization error
If you see an error like “Please enable the Virtual Machine Platform Windows feature”, verify that virtualization is enabled in your BIOS/UEFI:
# Check if virtualization is enabled
systeminfo | findstr /i "Hyper-V"
# Re-enable the required features
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all
WSL2 uses too much memory
By default, WSL2 can consume up to 50% of your total system memory. Create or edit C:\Users\yourname\.wslconfig:
[wsl2]
memory=4GB
swap=2GB
Then restart WSL2:
wsl --shutdown
DNS resolution fails inside WSL2
If ping google.com fails but ping 8.8.8.8 works, DNS is the issue:
# Temporary fix: manually set DNS
sudo rm /etc/resolv.conf
sudo bash -c 'echo "nameserver 8.8.8.8" > /etc/resolv.conf'
sudo bash -c 'echo "nameserver 8.8.4.4" >> /etc/resolv.conf'
# Prevent WSL from overwriting resolv.conf
sudo bash -c 'echo "[network]" > /etc/wsl.conf'
sudo bash -c 'echo "generateResolvConf = false" >> /etc/wsl.conf'
Then restart WSL2 with wsl --shutdown from PowerShell.
Clock drift between Windows and WSL2
After a Windows sleep/hibernate cycle, the WSL2 clock can drift:
# Check the clock
date
# Sync the clock manually
sudo hwclock -s
# Or on newer builds
sudo ntpdate time.windows.com
File permissions are wrong on Windows-mounted drives
# Add to /etc/wsl.conf inside your distribution
[automount]
enabled = true
options = "metadata,umask=22,fmask=11"
mountFsTab = false
”Cannot connect to Docker daemon” error
# Verify Docker Desktop is running on Windows
# Then check the WSL2 integration setting in Docker Desktop:
# Settings > Resources > WSL Integration > Enable for your distro
# Restart WSL2
wsl --shutdown
# Verify Docker works
docker ps
Summary
WSL2 transforms Windows into a first-class development platform for Linux-based workflows. With a real Linux kernel, native file system performance, Docker integration, and seamless VS Code connectivity, you can enjoy the best of both operating systems without compromise.
To get the most out of your WSL2 environment:
- Always store project files on the Linux file system for optimal performance.
- Use Windows Terminal with customized profiles for each distribution.
- Leverage VS Code Remote - WSL to keep your editing experience on Windows while executing everything in Linux.
- Configure
.wslconfigto manage memory and processor allocation for your workloads. - Use Docker Desktop with the WSL2 backend for container workloads — see our complete Docker installation guide for more details.
- Automate your workflows with CI/CD pipelines once your development environment is ready. Check our guide on Getting Started with GitHub Actions for CI/CD to take your projects to the next level.
With WSL2 properly configured, you have a powerful, flexible, and performant Linux development environment running right on your Windows machine.