WSL performance tweaks that work for me

I enjoy using Windows Subsystem for Linux (WSL). As compared to, say, running a Linux virtual machine in VirtualBox, or running Cygwin, WSL provides high operability between a Linux development environment with its Windows host environment without taking too much system resource or sacrificing too much performance (read: good enough). It’s almost like the best of both worlds to me.

While I don’t expect WSL to perform as fast as bare metal Linux, I was surprised when I first read the article published on Phoronix on a benchmark test done by Michael Larabel. WSL (more specifically, WSL2) even surpasses bare metal Ubuntu Linux in some areas such as Python and Nginx performance.

But that is just a benchmark test. In a real development workflow, there are other factors that can slow things down.

If you tried to experiment with WSL by running random stuffs that you were able to run natively on bare metal Linux, it’s quick to realise that some of the hacky customisations that you’ve done have made your WSL run slower than it used to.

The quickest way to work around it, is to deregister your slow WSL distribution and create a fresh WSL distribution.

But if you would prefer not to start afresh, here are a few tips to improve the performance of your WSL distribution. Both are based on my experience and experimentation when using WSL.

In fact, even if you decide to start afresh by resetting your WSL distribution, these tips can still be useful to make your WSL experience even smoother.

Tip #1: Disable passing of the $PATH environment variable values from Windows

If your shell prompt doesn’t show up instantly after you enter a command each time, it could be due to the some custom output in your prompt requires it to run some other commands before showing the prompt.

Having a long list of paths in your $PATH environment variable makes it harder for your shell prompt to locate the commands it needs to get ready to be run. To check if that is the case for you, simply check your $PATH environment variable in your WSL with the following command:

echo $PATH

By default, WSL automatically adds the items in Path environment variables (of both system and user) in Windows into the $PATH environment variable in the WSL. This can be easily verified by checking Windows’ Path environment variable through the System Properties UI in Windows (Win + Pause, or search for “View advanced system properties from Windows start menu).

My WSL $PATH environment variable shows a surprising lot of paths that I don’t use by default

As you can see in the examples in Path system environment variable in my Windows, it’s apparent that many developer tools that I installed on my Windows added themselves into the the system Path environment variable.

Having your WSL $PATH environment variable configured the same way as the Path environment variable in your Windows system allows you to run the Windows executable files (e.g. explorer, regedit etc.) that you are able to run in Windows command prompt without the need to specify the full paths. However, in most cases, you probably don’t need all of them.

To override WSL’s default behaviour to automatically add the Windows paths into a WSL distro’s $PATH environment variable, we can specify the overriding behaviour in the wsl.conf file.

WARNING: If your workflow requires you to frequently run some Windows commands from WSL, this will cause them to stop working on your WSL environment. One common example is the code command, which opens up Visual Studio Code in the WSL directory you run the command from. To fix that, you will need to add the command’s path manually into WSL $PATH environment variable. See step #3 below for more details.

  1. In your WSL distro, open /etc/wsl.conf with your preferred text editor as root. I’ll use nano here. If the file doesn’t exist, go ahead and create it.

    sudo nano /etc/wsl.conf

    NOTE: If you prefer to configure the setting globally for all your WSL distros, you can edit the .wslconfig file in your Windows %UserProfile% folder instead. Refer to the documentation for more details.

  2. Look for the [interop] section. Change the appendWindowsPath setting under the section to false. If the section or the setting doesn’t exist, go ahead and add it into the file. Once you’ve added it, it should look like the following. Save the file to proceed.

    appendWindowsPath = false
  3. Optionally, if you use Visual Studio Code with WSL, you will need to add the path of VS Code’s code command into your WSL $PATH environment variable for it to work. In your WSL, replace [Windows user name] in the following command accordingly and add it into your rc file e.g. the .bashrc file for Bash shell

    export PATH="$PATH:/mnt/c/Users/[Windows user name]/AppData/Local/Programs/Microsoft VS Code/bin"
  4. For the setting to take effect, you’ll need to relaunch the WSL distro. To terminate your WSL distro, open the Windows command prompt or PowerShell prompt as the administrator, and then replace [WSL distro name] in the following command accordingly and the run it:

    wsl -t [WSL distro name]

    NOTE: To find out about your WSL distro name, run the command wsl -l -v. Once done, wait for 8 seconds, then open your WSL terminal as usual, your WSL distro should now be running with the new setting. To verify that the $PATH environment variable no longer includes the paths from Windows, run echo $PATH again. To test out if VS Code with Remote WSL extension is working correctly, simply run code . in any WSL directory to see if it opens VS Code in the correct WSL folder with Remote WSL extension.

Tip #2: Exclude WSL directories with executables from being scanned by Windows Defender/Security

I found this idea from multiple sources. Please be warned that this could make your system less secure. You should assess your risk for doing so based on your use case. Proceed at your own risk.

Windows Defender’s real-time protection on WSL bin directories can sometimes cause high CPU usage. By excluding Windows Defender from proactively scanning WSL bin directories, we can reduce the occasional slow down of WSL. For this, you’ll need to identify the true Windows folder paths of the bin directories in your WSL distro, and add them into Windows Defender’s exclusion list.

I’m only using one WSL distro, and since Windows Defender allows us to use wildcard to specify the exclusions, there are only a handful of paths and processes to be configured in my case. I use the following steps to configure the exclusions:

  1. Open Windows Security program by searching for it from the start menu.

    Search for Windows Security program with the Windows 11 start menu
  2. Choose the ‘Virus & threat protection’ menu on the left. You should see the ‘Virus & threat protection’ page.

    The ‘Virus & threat protection’ page on Windows Security program
  3. Then, under the ‘Virus & threat protection settings’ section, click on the ‘Manage settings’ link. You’ll be on the ‘Virus & threat protection settings’ page.

    This is the settings page for virus & threat protection in Windows Security
  4. Look for the ‘Exclusions’ section at the bottom. Click on the ‘Add or remove exclusions’ link. You’ll be asked to give the permission for Windows Security to proceed further. Go ahead and click the Yes button.

    Scroll to the bottom to see the Exclusions section for virus & threat protection settings in Windows Security
  5. You can now add the exclusions. Below are some of the common paths to be excluded based on what I’ve added in my case. Remember to change the folder path according to your user name and the distro you installed.NOTE: The exclusions for ‘process’ are basically directories where executable files are stored in WSL. You may add other directories based on your usage of WSL. For example, if you use Golang, you should probably add /usr/local/go/bin/*; if you work on Flutter and FVM, you should probably add $HOME/fvm/default/bin/* and $HOME/fvm/versions/stable/bin/* etc.

    • ‘Folder’ exclusion: C:\Users\[Kaiden]\AppData\Local\Packages\[CanonicalGroupLimited.UbuntuonWindows_79rhkp1fndgsc]\LocalState
    • ‘Process’ exclusion: C:\Users\[Kaiden]\AppData\Local\Packages\[CanonicalGroupLimited.UbuntuonWindows_79rhkp1fndgsc]\LocalState\rootfs\bin\*
    • ‘Process’ exclusion: C:\Users\[Kaiden]\AppData\Local\Packages\[CanonicalGroupLimited.UbuntuonWindows_79rhkp1fndgsc]\LocalState\rootfs\sbin\*
    • ‘Process’ exclusion: C:\Users\[Kaiden]\AppData\Local\Packages\[CanonicalGroupLimited.UbuntuonWindows_79rhkp1fndgsc]\LocalState\rootfs\usr\bin\*
    • ‘Process’ exclusion: C:\Users\[Kaiden]\AppData\Local\Packages\[CanonicalGroupLimited.UbuntuonWindows_79rhkp1fndgsc]\LocalState\rootfs\usr\local\bin\*
    • ‘Process’ exclusion: C:\Users\[Kaiden]\AppData\Local\Packages\[CanonicalGroupLimited.UbuntuonWindows_79rhkp1fndgsc]\LocalState\rootfs\usr\sbin\*
    • ‘Process’ exclusion: C:\Users\[Kaiden]\AppData\Local\Packages\[CanonicalGroupLimited.UbuntuonWindows_79rhkp1fndgsc]\LocalState\rootfs\home\[kaiden]\bin\*
      The exclusion lists that I’ve configured for my machine

That’s it! Those are the two tips I have for now. Feel free to share with me yours too!

An Ode to Windows Subsystem for Linux (WSL)

I’ve always been enjoying running my Linux-based development workflows on a Windows machine with Windows Subsystem for Linux (WSL). Even on a day when I don’t do any development work, I would still open up my Windows Terminal to run the sudo apt update and sudo apt upgrade -y command. Keeping my Linux system up-to-date manually somehow gives me a sense of blissfulness.

I’ve always been more comfortable working with UNIX-based environments. I got in touch with Linux when I was attending my pre-U programme. I installed it on my desktop PC and used it as my daily driver. Then I started to meddle with Hackintosh to try out macOS. When I started working, the first personal laptop that I got myself with was a MacBook Pro. Throughout my days with Linux, Hackintosh and my first MacBook Pro, I just had to make sure that the machines are configure with dual boot (or triple boot when I started to use Hackintosh) for Windows. I always had to reboot the machine to switch between the OSes for apps or tools exclusive on each of them.

When Microsoft announced WSL a few years ago, I was so excited about it. Back then, my MacBook Pro was aging and I was looking to get a new laptop. But the then-current generation of MacBook Pro with the touch bar was really deterring me from getting one due to various issues other buyers were experiencing. I was considering to get a laptop that comes natively with Linux, but pretty much all major laptop brands here in Malaysia shipped their products bundled with Windows. Having dealt with hardware drivers on Linux on desktop machines in the past, I was concerned about the same issue on a laptop, given how limited after-market hardware customisation can be done on a laptop machine. So the release of WSL bridged my needs for using my UNIX-based development workflows on a Windows laptop and saved me from the difficulty in selecting the right laptop to purchase.

The version 2 of WSL was released not long after the first version of WSL was released. WSL2 has also been an improvement for my workflow. I find it noticeably faster then its predecessor. Microsoft’s partnership and collaboration with the Docker team to port Docker for Windows to be powered by WSL2 instead of Hyper-V or VirtualBox also gave Docker for Windows a performance boost. The seamless integration of Visual Studio Code within WSL also makes the development flow much smoother.

Building on top of WSL, Microsoft also recently released Windows Subsystem for Android (WSA). Although it is not officially available in Malaysia, a fan of WSL like me would figure out a way to get their hands on it. Given that Android is based on Linux, the possibility of having Android running in the Windows environment, just like how Linux can through WSL has long been speculated. WSA could make mobile apps development much easier for developers. At the time of writing, I’m still tinkering with my WSL and WSA to establish a smooth Flutter development workflow involving the two. The possibility to have these workflows running harmoniously and seamlessly simply excites me.

I really appreciate and applaud Microsoft’s effort in embracing Linux and FOSS in general, as opposed to strictly opposing them years before. As a result of this change of their stance, we get good stuffs like WSL, Docker for Windows, Visual Studio Code, and many of the enhancements on GitHub etc. It makes the experience as a developer much more pleasant for me.


I have a love-hate relationship with journalling. The purpose of this blog is supposed to be for me to keep a journal regularly, but clearly, I have not been doing that.

I love writing. I enjoy the creative process when I write. When I’m feeling inspired, I could sense the words that I need to express my thoughts surfacing in my brain, as if they are surfacing out of a sea of my not-quite-extensive vocabulary.

Probably due to the fact that I’m not a native speaker of English, sometimes they don’t surface in the correct grammatical order, or they are wrongly spelled without hyphens, or the best choice of words don’t surface from the first attempt.

As I’m typing the words out, I often have to move the cursor back and forth to do some edits. Sometimes, I would quickly whip up a new browser tab to verify the correct usage of a word that I’m about to use. As I’m doing the verification, sometimes I would be drawn into the rabbit hole and start to read about other things remotely related.

When I’m out of the rabbit hole, I would usually wrap up the creation process of a sentence by reading it, both silently and out loud, to make sure that I’m happy with it. Nevertheless, I always gain a little sense of satisfaction for meticulously completing even a small paragraph in the most beautiful and befitting way I can, as if I’m an artist that completed an masterpiece.

Come to think about it, maybe I should write a book.

But what I hate about writing, is that I always take too much effort in crafting my sentences, to the point that I often could not complete the whole writing. Being very busy for my job as a CTO, I often can’t afford the time to write the way I enjoy—in the meticulous manner.

That is why I have not been writing in this blog for such a long time. It is evident because the last time I wrote here was when I first landed on the role of CTO in my former company.

After years of helming several start-ups as the CTO since 2016, I’ve come to question myself, whether is it just me, or this job really expects so much from a person. Anyway, I have a lot more thoughts on that topic and it is going to need a separate post on its own.

In the meantime, since I’m no longer attached to and employed full-time by any companies, I would take the opportunity to enjoy journalling while I still can. When I’m back being a start-up CTO again (if it happens at all), hopefully I would have figured out how to write regularly while being in the job.

The Path to Agility

Two months ago, my CEO wanted me to learn about Scrum and to implement it in the company. I went on researching on it, and found out that it does not fit exactly well in our organisation due to the facts that:

  • We have multiple products but only one development team.
  • We have ad hoc jobs and tasks from the C-level bosses from time to time.
  • We don’t really have a fully cross-functional team. Specifically, we don’t have designers.

So I went on to create our own variation of Scrum, and to rename some of the terminologies to make it simpler for the guys.

Then one of my colleagues pointed out that I should attend a ScrumMaster course to really learn about it. I thought that was a good idea as I needed to validate if I’m practicing Scrum correctly.

So, last month, I attended a Scrum course. I’ve gained a much, much better understanding of Scrum. I realised that what I did was only performing some processes of Scrum, but not understanding the basis of running these processes. The variation of Scrum we were practicing was only processes to keep things in order in some ways, but does not really increase productivity or product quality.

After attending the course, I understand the core values, pillars, ideals of Scrum. I understand the various roles and the parts they play to contribute to produce a good software product. I understand the purpose of each ‘ceremony’ in Scrum. To run Scrum the most effective way, there’s really nothing in the Scrum framework that can be removed just to adept to the organisation.

In fact, the more I understand about Scrum, the more I find it suitable for our organisation and products. After some long consideration of the case of our organisation, I really think the full, non-discounted version of Scrum is the best way for us. There are always logistic issues and human factor that become the obstacles for the change, but I’m very convinced and determined to help my company to become a truly Agile company with Scrum.

And yeah, I am now a certified Professional Scrum Master.

Sticking with Twenty Eleven

I haven’t been updating this blog for exactly two years! Time really has passed.

I have been keeping the copy of WordPress that hosts my blog updated, but I haven’t been keeping the contents updated for quite a while. So when I click through the admin’s GUI, I found out that throughout the years that I’ve not been keeping the contents updated, two default WordPress themes have been released, which are Twenty Twelve and Twenty Thirteen.

Twenty Twelve looks bland. I didn’t even bother to preview it.

Twenty Thirteen looks too loud. The colour choice is too bright and all of the default header images are too distractive.

Twenty Eleven still looks better. Simple and elegant.

So I’m still going to stick with Twenty Eleven even though it’s 2013 now.