My developer workflow using WSL, tmux, and VSCode

8 November, 2022 | 6 min read

Windows Terminal

WSL has made development on Windows machines much better. Especially with the release of WSL 2 it is now easier and faster than ever.

This post documents my workflows and tools for software development on Windows. I will update it whenever I find a better way to do something.

I use the Ubuntu distribution for WSL. This is also the OS I use (or derivations thereof: PopOS) when I'm on Linux.

For configuration of the mentioned tools, look at my dotfiles.
Love finding new tools? Check out my tool stack!


Windows Terminal is a non-negotiable for me. I have not found a better terminal emulator for Windows. It has tabs, great customizability, and it's pretty powerful.

I use a Nerd Font called CascaydiaCove Mono in the terminal. I switch between the Campbell and One Half Dark themes.


I use Z Shell, aka. zsh.

Managing zsh can get kind of trivial, so like Oh My Zsh has been essential to my workflow. It makes configuration and plugin management easy.


I was a huge fan of Powerlevel10k for Zsh, but moved to Starship because it has a clean and minimal default look. Starship is very easy to set up and provides a nice developer experience in my opinion.

CLI tools

I use an array of CLI tools to make me more effective. Here's a rapid-fire list:

  • Lazygit for accelerated git workflow
  • Exa as a better ls replacement
  • gh (GitHub CLI) for faster GitHub workflow
  • tmux for awesome multi-tasking in the terminal
  • nvm to manage node versions
  • Multiple Zsh plugins (see below)
  • Lazydocker for accelerated docker workflow
  • Brew for package management
  • Act for running GitHub Actions locally. Save yourself the painful embarrasment of pushing ** commits and waiting for CI to fail while you're figuring out how to do X and Y in your CI
  • Ni so I don't have to care whether I'm in a Yarn / NPM / pnpm project


This is my favorite way of interacting with git. My git capabilities and speed has probably 10x'ed after I started using it.

I have configured my Lazygit to work with git-delta and commitizen.

Jesse Duffield, the creator of Lazygit, made a great video showcasing 15 features in 15 minutes. I highly recommend that you watch it to see how it might accelerate your workflow.

Git-delta is a great tool for visualizing changes.

Commitizen helps me write conventional commits, which is makes it easier to manage versions with semantic release when creating either node packages, Obsidian plugins, and other software where it makes sense to use that kind of versioning.


Great replacement for ls.

I use a few aliases here:

alias ll="exa --long --group --icons --git --header"
alias llt="exa --oneline --tree --icons --git-ignore"
alias ls="exa --icons --git"

To install, use cargo and do cargo install exa.

GitHub CLI

I mainly use this to create and configure repos. Often also do gh repo view --web to open the repo in my browser.

  • gh repo create to create a new repo. --private to make it private.
  • gh repo view --web to open the repo in the browser.
  • gh repo clone <repo> to clone a repo, e.g. gh repo clone chhoumann/dotfiles. No need to prepend your own username to the repo name (given you own the repo).
  • gh pr merge -d to merge the PR for the branch you are in and delete the branch.

One of my most time-saving combinations comes into play when I'm initializing a new repository.

# Make project folder and cd in
mkdir project1 && cd project1
# Initialize new git repository
git init

# Many project-starters like `npx create-next-app@latest` will create a folder for you
# And sometimes even init a git repo. That's why the command below is great.

# Create a new GitHub repository and push local repo up
gh repo create project1 --private --source=. --remote=upstream 

# Alternatively, if you just want gh to create an empty repo and clone it to a folder:
gh repo create project1 --private --clone


I'm still learning tmux, but even the basics have accelerated my workflow.

Creating and killing panes, splitting panes, and switching between them is very fast and easy.

This seriously helps when, e.g. you are running npm run dev in one pane, but need to commit something. You don't want to stop the dev server, so you just split the pane and commit in the new pane.


I basically just do nvm alias default lts/gallium (current LTS version). This sets the default node version.

nvm use --lts or nvm install --lts is very helpful.

Sometimes you want to play around with other versions (e.g. latest or previous), so it helps with that as well.

Zsh plugins

I'm using the following plugins:

  • git adds nice git aliases, but I prefer Lazygit now
  • zsh-z so you can jump around directories much faster
  • gh adds completion for the gh cli
  • rust adds completion for the rust compiler, rustup, and cargo
  • zsh-autosuggestions adds autosuggestions
  • tmux adds QoL features for using zsh & tmux together.

If you choose nothing else, I highly recommend zsh-z. It's a game changer. You can CD into a directory from anywhere by just writing part of it.

For example, z dot takes me to my dotfiles folder, no matter where I am. It learns from your usage, so it gets better over time.


I use Visual Studio Code as my editor.

I've dabbled in Neovim, but decided I'd rather spend my time doing other things than tweaking my Neovim config. I have a tendency to fall into rabbit holes, especially ones that look like shiny new tools.

Using VS Code is a good way to get a lot of functionality without having to spend a lot of time configuring it. This also makes setup much easier when switching computers.


I use the following extensions:

And language specific extensions for the languages I use.

I use GitHub Dark as my primary theme. I've also taken a liking to poimandres and poimandres-alternate.

Liked this post? Join the newsletter.