Setting up development environment in Windows Subsystem for Linux (WSL) in Windows 11

RemekGdansk
10 min readJan 2, 2023

--

Introduction

This guide assumes basic knowledge of using Windows PowerShell and Linux Bash or Zsh.

Many development tools tend to be available in Linux first. On the other hand, systems such as Windows and macOS are generally considered more convenient in daily use. Moreover, in the working environment, one might not have a possibility to use Linux.

However, with the introduction of Windows Subsystem for Linux and especially its most recent updates, one can use Windows UI and access all Linux development tools.

Purpose of this guide is to describe an example setup of a Linux development environment in Windows 11. Due to my personal working experience, I will provide examples for Docker, Java, IntelliJ IDEA, Node.js and Visual Studio Code. Nevertheless, basic steps will be useful regardless of the programming languages or IDEs used. People working in other technologies are encouraged to provide guides relevant for their domains in the comments.

In the beginning, I would like to highlight that the guide uses WSL 2. WSL 2 is the newest version at the moment of writing this guide and the recommended one. Differences between WSL 1 and WSL 2 are described in detail here: https://learn.microsoft.com/en-us/windows/wsl/compare-versions. From our perspective, we need to keep in mind that there is a poor performance for WSL 2 reaching Windows file system and vice versa. This is why we are going to use WSL 2 filesystem for storing all source code, scripts, software packages and so on. For the rest of the guide, I will use only the term WSL, but it will refer to WSL 2 only.

WSL Installation

WSL can be installed by following this guide: https://learn.microsoft.com/en-us/windows/wsl/install. Note that using the default command wsl --install will install the default Linux distribution. You can check what is the default Linux distribution by running wsl --list --online. Sample output:

PS C:\Users\Remek> wsl --list --online
The following is a list of valid distributions that can be installed.
The default distribution is denoted by '*'.
Install using 'wsl --install -d <Distro>'.

NAME FRIENDLY NAME
* Ubuntu Ubuntu
Debian Debian GNU/Linux
kali-linux Kali Linux Rolling
SLES-12 SUSE Linux Enterprise Server v12
SLES-15 SUSE Linux Enterprise Server v15
Ubuntu-18.04 Ubuntu 18.04 LTS
Ubuntu-20.04 Ubuntu 20.04 LTS
OracleLinux_8_5 Oracle Linux 8.5
OracleLinux_7_9 Oracle Linux 7.9

Here, Ubuntu with an undefined version is the default. In fact, it is equivalent to installing the package from Windows Store. If you open Windows Store after running wsl --install and rebooting your system, you will see that packages Windows Subsystem for Linux and Ubuntu are already installed. You can read more in this blog post: https://devblogs.microsoft.com/commandline/the-windows-subsystem-for-linux-in-the-microsoft-store-is-now-generally-available-on-windows-10-and-11/.

So, in a nutshell, if you would like to follow the defaults:

  1. Open Terminal as an Administrator.
  2. Run wsl --install.
  3. Reboot.
  4. Set your Linux username and password.

This is it. Let’s continue to the next section. The rest of the guide assumes that the defaults were used.

First Steps in WSL

You should be now in your WSL environment already. If not, open the Terminal and just type wsl:

PS C:\Users\Remek> wsl
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

remek@Host:/mnt/c/Users/Remek$

Additionally, a new profile should be added to your Terminal. This is another way to run it:

Ubuntu profile added to Terminal after running the default installation.

From now on, you can run any Linux command you would like. At first, run explorer.exe . — it will open the current folder in Windows explorer. In my example, it is a folder in the Windows filesystem — my Windows user directory. It is accessible from Linux under the /mnt/c/Users/Remek path. You can quickly move to your Linux user’s directory by running cd ~, which will be the following path:

cd ~
remek@Host:~$ pwd
/home/remek

You can also open Linux path in Windows Explorer as well by running explorer.exe . . As mentioned before, communication between Windows and Linux filesystems is slow, but as we can see, either is accessible from another.

Before installing any new software, let’s update the current packages. You need to do this as a superuser, therefore commands are preceded by sudo and need to be confirmed with the user’s password:

sudo apt update  # Update information about the available packages
sudo apt upgrade # Upgrade packages

Optional: Installing Zsh

The default shell in Ubuntu is Bash. Installing https://en.wikipedia.org/wiki/Z_shell is optional, but the following examples will use Zsh. The actual commands should be the same for both Bash and Zsh.

If you would like to use Zsh and Oh My Zsh (Oh My Zsh supports Zsh configuration with plugins, themes and so on), please follow instructions on Oh My Zsh page: https://github.com/ohmyzsh/ohmyzsh/wiki.

Zsh is easily configurable with plugins and themes. In the example below, I display the commands’ running time:

Customized Linux shell

Customizing shell is out of scope of this guide. However, shell presented in the screenshot above is Zsh with https://github.com/romkatv/powerlevel10k theme.

Git

Git should be installed by default. You can check it by running:

git --version

If you get version of Git, you can continue to the next section. If you get command not found, install Git via apt:

sudo apt install git

Docker

Follow Docker for Windows instructions for WSL 2 Backend (and not Hyper-V) in https://docs.docker.com/desktop/install/windows-install/. At the moment of writing this guide, individuals using Docker for Windows do not need a paid subscription.

After a reboot, you should be able to run Docker commands from WSL. You can check your installation by running:

docker run hello-world

Java

I recommend using https://sdkman.io/ for managing your JVM-related SDKs. You can follow official instruction from https://sdkman.io/install. The following example shows how to install SDKMAN and two Java distributions:

sudo apt install unzip zip # Required for SDKMAN! installation
source .zshrc # Bash: `source .bashrc`
curl -s "https://get.sdkman.io" | zsh # Bash: `| bash`
source .zshrc # Bash: `source .bashrc`
sdk version # Should return SDKMAN version
sdk list java # See all available Java SDKs
sdk install java 17.0.5-tem # Install Temurin 17.0.5 Java distribution
sdk install java 19.0.1-tem # Install Temurin 19.0.1 Java distribution
java --version # See the currently used version

You can switch currently used Java SDK by running sdk use java <version>, for example:

sdk use java 17.0.5-tem
# Or
sdk use java 19.0.1-tem

However, this change will only affect this shell. For example, if you switched from 17 to 19 and you open a new shell, java --version will return 17.

You can change the default Java SDK that new shell uses by running sdk default java <version>. Example:

sdk default java 19.0.1-tem

Note that changing the default SDK will not affect the current shell.

In addition, let’s install Maven — a popular build tool for Java projects:

sdk list maven | cat # See what Maven versions are available
sdk install maven 3.8.7 # You can choose any available version you want
mvn -version # Confirm that Maven was installed correctly

Let’s run a Java project now — a SpringBoot application:

  1. Go to https://start.spring.io/ and generate a project. Use Maven, Java 17 and Jar. Add “Spring Web” dependency. Leave everything else as defaults and click Generate.
  2. Save the downloaded .zip file to your WSL user folder.
  3. Run unzip demo.zip from your home folder. Project will be extracted to the ~/demo folder.
  4. Go to ~/demo folder and run mvn clean install.
  5. Run mvn spring-boot:run to start the application.
  6. Now you can open localhost:8080 in the browser or curl localhost:8080 from either Windows or WSL. You will get 404 response from your application.
  7. Now you can stop the application with Ctrl+C.

IntelliJ IDEA

Having Java installed, let’s configure IntelliJ IDEA (which is a very popular Java IDE) to work with WSL.

IntelliJ IDEA supports WSL natively. You can follow the official guide here https://www.jetbrains.com/help/idea/how-to-use-wsl-development-environment-in-product.html, although you can skip steps related to WSL installation as you have WSL installed already.

At the moment of writing this guide (January 2023), I experienced problems with IntelliJ IDEA — WSL interoperability. It turned out to be a Windows Defender issue reported in https://github.com/microsoft/WSL/issues/8995. I had to disable Windows Defender and use another antivirus to proceed with IntelliJ IDEA and WSL. If the issue linked above is solved, you can try using IntelliJ IDEA with WSL with Windows Defender enabled.

In our walkthrough, we will work on the SpringBoot application created in the previous section.

  1. Install IntelliJ IDEA on Windows. You can use https://www.jetbrains.com/toolbox-app/ for convenience.
  2. Run IntelliJ IDEA and open the project located in the WSL filesystem. Path will be prefixed with \\wsl$, like \\wsl$\Ubuntu\home\<username>\demo.
  3. Open IntelliJ IDEA Terminal — it should already use WSL shell. You can use it to run any commands, like changing Java version via SDKMAN.
  4. Open file DemoApplication in IntelliJ IDEA.
  5. Add helloWorld() method there as well as annotations @RestController and @RequestMapping("\"). The file should look like this (package statement omitted, as yours might be different):
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@RestController
@RequestMapping("/")
public class DemoApplication {

public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}

@GetMapping
String helloWorld() {
return "Hello World";
}
}

Now, when you run the application from IntelliJ IDEA, opening localhost:8080 in a browser or running curl localhost:8080 will return “Hello World” instead of a 404 error.

Although you are running IntelliJ IDEA from Windows, all files and tools are located in WSL, which was the objective.

Node.js

As SDKMAN facilitates working with different Java version, Node Version Manager (NVM) does the same for Node.js.

Full instructions can be found here: https://github.com/nvm-sh/nvm#installing-and-updating. For our case, we need to do the following:

# Remark: change the version to the newest one
# You need to pipe the install script to Bash even if you are using Zsh
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash
source ~/.zshrc # Reloads shell configuration; use source ~/.bashrc for Bash.

Check if installation went successfully by running nvm --version.

Now, let’s install Node.js using NVM:

nvm install --lts # Install the newest LTS version of Node
nvm install node # Install the newest version of Node

You can list all installed Node.js version by running nvm ls:

nvm ls
# Explicit versions
v18.12.1
-> v19.3.0
# Available aliases
default -> lts/* (-> v18.12.1)
iojs -> N/A (default)
unstable -> N/A (default)
node -> stable (-> v19.3.0) (default)
stable -> 19.3 (-> v19.3.0) (default)
lts/* -> lts/hydrogen (-> v18.12.1)
lts/argon -> v4.9.1 (-> N/A)
lts/boron -> v6.17.1 (-> N/A)
lts/carbon -> v8.17.0 (-> N/A)
lts/dubnium -> v10.24.1 (-> N/A)
lts/erbium -> v12.22.12 (-> N/A)
lts/fermium -> v14.21.2 (-> N/A)
lts/gallium -> v16.19.0 (-> N/A)
lts/hydrogen -> v18.12.1

The currently used Node.js version is denoted with an arrow ->. You can also check the current version by running:

nvm current
v19.3.0
# Or
node --version
v19.3.0

Node version can be switched with nvm use command and by providing versions or aliases. For available aliases, see nvm ls command mentioned earlier. Examples:

# Use explicit version
nvm use v18.12.1
Now using node v18.12.1 (npm v8.19.2)

node --version
v18.12.1

# Use version alias for the newest Node.js
nvm use node
Now using node v19.3.0 (npm v9.2.0)

node --version
v19.3.0

# Use version alias for the newest LTS Node.js
nvm use default
Now using node v18.12.1 (npm v8.19.2)

node --version
v18.12.1

We are now ready to complete our Node.js development environment in WSL with Visual Studio Code.

Visual Studio Code

In order to work with Visual Studio Code in WSL, we can follow selected steps of the official tutorial https://code.visualstudio.com/docs/remote/wsl-tutorial.

  1. Install Visual Studio Code in Windows.
  2. Run Visual Studio Code
  3. Install WSL extension in Visual Studio Code.
  4. Press F1 and type “WSL”. Run WSL: New WSL Window command.
  5. New Visual Studio Code window will open. You can see whether Visual Studio Code is running in Windows or WSL by looking at the bottom-left corner:
Indicator of Visual Studio Code running in WSL

Now, let’s write some Node.js code & run it in WSL:

  1. Open your WSL Terminal and create a folder node-demo in WSL filesystem.
  2. In Visual Studio Code instance running on WSL, click File, then Open Folder... and choose previously created node-demo folder. (You can do it also from the Visual Studio Code instance running in Windows. Visual Studio Code will then notify you that it is recommended to run Visual Studio Code in WSL when working in WSL filesystem and give you the possibility to reopen the node-demo folder in Visual Studio Code WSL instance.)
  3. Create a new file app.js and paste contents of a simple Node.js app from the official Node.js tutorial https://nodejs.org/en/docs/guides/getting-started-guide/.
  4. Run the application with command node app.js and test it by calling curl localhost:3000 or opening the localhost:3000 address in a browser.

There is also another convenient way to open a project in Visual Studio Code — directly from Terminal via code command (reopen WSL Terminal if code command is not available):

cd node-demo # Move to project folder
code . # Open Visual Studio Code in the current folder

Conclusion

With the recent updates of WSL and growing tool support for WSL, it is now completely feasible to work on Windows with a full set of Linux-based development tools, including scripting and shell improvements. The new popular approach might be to have all development tools installed in WSL and use Windows for typical Windows applications as Office suite.

Please feel free to share in the comments other tutorials related to development in WSL & let me know if anything was unclear or got outdated.

--

--