Optional extras
Personalise the environment. Nothing here is needed for the rest of the guide to work, and every recipe says how to undo it.
Shell
Switch your shell to zsh#
Optional. Replace bash with zsh plus autosuggestions and syntax highlighting, and keep mise working.
Optional. Bash from the baseline setup works for everything in this guide. Do this if you want history-based suggestions and command highlighting as you type.
When to use it#
You spend most of the day in the terminal and want a more helpful interactive shell. It changes nothing about how projects build or run.
Prerequisites#
- The baseline setup done, including mise in
~/.bashrc(step 5).
Steps#
-
Install zsh and the two plugins most people want:
WSLzsh and plugins sudo apt install -y zsh zsh-autosuggestions zsh-syntax-highlighting -
Create
~/.zshrcwith mise activation and the plugins. Syntax highlighting must be the last line:File~/.zshrc autoload -Uz compinit && compinit -C eval "$(~/.local/bin/mise activate zsh)" source /usr/share/zsh-autosuggestions/zsh-autosuggestions.zsh source /usr/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh # must be last -
Make zsh your login shell, then close and reopen the terminal:
WSLChange the default shell chsh -s "$(which zsh)"If zsh shows its first-run menu, press q; your
~/.zshrcalready exists.
More tools that plug into ~/.zshrc (fuzzy history, smarter cd, a prompt): A fast prompt and Modern command-line tools.
Verify#
echo $SHELLprints/usr/bin/zsh.which nodestill prints a path under~/.local/share/mise.- Typing the start of a previous command shows the rest in grey; → accepts it.
time zsh -i -c exitreports well under 0.2 s.
Troubleshoot#
node: command not foundafter switching: the mise line is missing from~/.zshrc, or saysactivate bash. It must sayactivate zsh.- Startup feels slow: comment lines out of
~/.zshrcone at a time and re-runtime zsh -i -c exit.compinitwithout-Cand Windows interop lookups are common causes.
Undo#
chsh -s /bin/bashReopen the terminal. ~/.zshrc can stay; bash ignores it.
Shell
A fast prompt with Starship#
Optional. A prompt that shows Git branch, runtime versions and command duration, with a Nerd Font so its icons render.
Optional. A plain prompt works fine; this one adds context at a glance.
When to use it#
You want the current Git branch, dirty state, runtime version and how long the last command took, without a slow prompt framework.
Prerequisites#
- bash or zsh.
curl(installed in setup step 2).
Steps#
-
Install a Nerd Font on Windows, for example JetBrainsMono Nerd Font from nerdfonts.com: unzip, select the
.ttffiles, right-click → Install. -
Select it in Windows Terminal (Settings → Ubuntu → Appearance → Font face) and in your editor’s terminal font setting.
-
Install Starship into your home directory (no
sudoneeded):WSLInstall Starship mkdir -p ~/.local/bin curl -sS https://starship.rs/install.sh | sh -s -- -b ~/.local/bin -
Add the init line after mise activation, then reopen the terminal:
File~/.zshrc (or ~/.bashrc with: starship init bash) eval "$(starship init zsh)"
Verify#
The prompt shows the folder and, inside a Git repo, the branch. Icons render as symbols, not empty boxes. Run sleep 3: the next prompt shows the duration.
Troubleshoot#
- Boxes or question marks instead of icons: the terminal font is not a Nerd Font. Fonts are chosen on Windows, not in Linux.
starship: command not found:~/.local/binis not onPATH. Ubuntu adds it at login if the folder exists; open a new terminal after step 3.
Undo#
Remove the starship init line and run rm ~/.local/bin/starship.
Shell
Modern command-line tools#
Optional. fzf, zoxide, direnv, eza, bat, ripgrep, delta, lazygit, atuin and friends, with the init order that keeps zsh fast.
Optional. Each tool is independent; install the ones you’ll use.
When to use it#
You want faster search, fuzzy history, per-project environment variables and nicer diffs in the terminal.
Prerequisites#
- zsh (the init block below is for zsh; most tools also have bash equivalents).
- mise from setup step 5, for the tools not packaged in Ubuntu.
Steps#
-
Tools packaged by Ubuntu:
WSLFrom apt sudo apt install -y fzf zoxide direnv eza bat fd-find ripgrep jq btop tmux git-deltaezaandgit-deltaare in Ubuntu 24.04’s repositories; on older releases install them withmise use -ginstead. -
Tools Ubuntu doesn’t package (or packages old versions of), via mise:
WSLFrom mise mise use -g lazygit atuin dust lazydocker -
Wire them into
~/.zshrc. Order matters: keep mise first and syntax highlighting last. Leave out lines for tools you didn’t install.File~/.zshrc: init order autoload -Uz compinit && compinit -C eval "$(~/.local/bin/mise activate zsh)" eval "$(starship init zsh)" # if you use the prompt eval "$(direnv hook zsh)" source /usr/share/doc/fzf/examples/key-bindings.zsh eval "$(atuin init zsh --disable-up-arrow)" eval "$(zoxide init zsh --cmd cd)" # late: after other cd/chpwd hooks alias bat=batcat fd=fdfind # Ubuntu package names alias ll="eza -la --git --group-directories-first" alias lg=lazygit source /usr/share/zsh-autosuggestions/zsh-autosuggestions.zsh source /usr/share/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh # must be last -
Use delta for Git diffs (only after
git-deltais installed, or Git can’t show diffs):WSLdelta as Git's pager git config --global core.pager delta git config --global delta.navigate true
What you get#
| Keys / command | What it does |
|---|---|
| → on grey text | Accept autosuggestion from history |
| Ctrl+R | Fuzzy history search (atuin: folder, exit code, duration) |
| Ctrl+T / Alt+C | Fuzzy-pick a file path / jump into a subfolder |
cd proj | zoxide: jump to your most-used folder matching “proj” |
.envrc + direnv allow | Per-project env vars, loaded on cd in and unloaded on the way out |
tmux new -s app / tmux a -t app | Sessions that survive closing the terminal tab |
rg pattern / fd name | Fast content and file-name search |
lg / lazydocker | Git and Docker in a terminal UI |
dust -d 2 ~ | What is using disk space |
Verify#
Open a new terminal. Ctrl+R opens a searchable history, ll lists files with Git status, and git diff shows side-by-side colour. time zsh -i -c exit should stay under 0.2 s.
Troubleshoot#
command not found: atuin(or another mise tool): mise activation must come before its init line.git diffprints nothing or errors:core.pagerisdeltabut delta isn’t installed. Install it or rungit config --global --unset core.pager.- Ctrl+R shows fzf instead of atuin: atuin’s init must come after the fzf key bindings.
Undo#
Remove the lines from ~/.zshrc, then uninstall what you no longer want: sudo apt remove <package> for apt tools, mise unuse -g <tool> for mise tools, and git config --global --unset core.pager for delta.
Windows integration
Call Windows apps without the Windows PATH#
Optional. Stop Windows' PATH leaking into Linux for a faster shell and no node/npm mix-ups, then add back only code, Explorer, the clipboard and PowerShell.
Optional. The default (Windows PATH appended) works; this trades a little setup for a faster, more predictable shell.
When to use it#
Command lookup feels slow, or which node sometimes finds the Windows install under /mnt/c. Skip this if neither bothers you.
Prerequisites#
- Know the consequence: with
appendWindowsPath=false,code,cursor,explorer.exeandpowershell.exeare no longer found until step 2 adds them back. Do both steps together. - Editor installed on Windows (Open a WSL project in your editor).
Steps#
-
Turn the Windows PATH off in /etc/wsl.conf (
sudo nano /etc/wsl.conf):File/etc/wsl.conf (sudo) [interop] enabled=true appendWindowsPath=false -
Add back what you use, in a file both bash and zsh can source:
File~/.config/shell/common.sh _win=/mnt/c/Windows _winuser=$(wslpath "$($_win/System32/cmd.exe /c 'echo %USERPROFILE%' 2>/dev/null | tr -d '\r')") _apps="$_winuser/AppData/Local/Programs" [ -d "$_apps/Microsoft VS Code/bin" ] && export PATH="$PATH:$_apps/Microsoft VS Code/bin" [ -d "$_apps/cursor/resources/app/bin" ] && export PATH="$PATH:$_apps/cursor/resources/app/bin" alias open="$_win/explorer.exe" # open . → Explorer here alias clip="$_win/System32/clip.exe" # echo hi | clip alias pwsh="$_win/System32/WindowsPowerShell/v1.0/powershell.exe" alias winget="$_winuser/AppData/Local/Microsoft/WindowsApps/winget.exe" unset _win _winuser _apps -
Source it from your shell’s rc file, then restart WSL from PowerShell with
wsl --shutdown:WSLLoad it in bash (use ~/.zshrc for zsh) mkdir -p ~/.config/shell echo 'source ~/.config/shell/common.sh' >> ~/.bashrc
Verify#
echo $PATH | tr ':' '\n' | grep -c /mnt/cprints1or2(only the editor folders), not dozens.code .opens VS Code with WSL: Ubuntu;open .opens Explorer.which nodepoints into~/.local/share/mise.
Troubleshoot#
code: command not found: the install folder differs (system-wide installs live inC:\Program Files\Microsoft VS Code\bin). Adjust the path incommon.sh. More: A Windows command is not found.- Nothing changed:
/etc/wsl.confis only read at start. Runwsl --shutdownin PowerShell.
Undo#
Set appendWindowsPath=true (or delete the line) in /etc/wsl.conf, remove the source line, and run wsl --shutdown.
Windows integration
Make Windows Terminal open in Linux#
Optional. Make Ubuntu the default Windows Terminal profile, start tabs in your Linux home, and learn the handful of keys worth knowing.
Optional. A convenience for people who open terminals all day.
When to use it#
New terminal tabs open PowerShell, or open Ubuntu in /mnt/c/Users/<you> instead of your Linux home.
Prerequisites#
- Windows Terminal (included with Windows 11).
- Ubuntu installed (setup step 1).
Steps#
-
Windows Terminal → Ctrl+, → Startup → Default profile: Ubuntu.
-
Profiles → Ubuntu → Command line:
PowerShellUbuntu profile command line wsl.exe -d Ubuntu --cd ~ -
Optional: Appearance → Font face to a Nerd Font if you use a prompt with icons.
-
Save.
Keys worth knowing#
| Keys | What it does |
|---|---|
| Ctrl+Shift+T | New tab (default profile) |
| Ctrl+Shift+Space | Profile menu |
| Alt+Shift+D | Split pane |
| Alt+arrows | Move between panes |
| Ctrl+, | Settings |
Verify#
Ctrl+Shift+T opens Ubuntu, and pwd prints /home/<you>.
Undo#
Set Default profile back to Windows PowerShell and clear the custom command line (the profile’s default is wsl.exe -d Ubuntu).
Conveniences
Small conveniences#
Optional. Clipboard, path conversion, opening URLs and Explorer from Linux, Linux GUI apps, public URLs, throwaway distros and other small time-savers.
Optional. Each item stands alone; none of them is needed elsewhere in this guide.
Windows from Linux#
- Open Explorer here:
explorer.exe .opens the current Linux folder in Windows. - Clipboard both ways:
cat key.pub | clip.exe. In tmux copy mode, pipe the selection toclip.exe. - Translate paths:
wslpath -w .gives a Windows path;wslpath 'C:\Users'goes the other way. - Open URLs in the Windows browser: install
wsluand setBROWSER=wslview, so CLI logins (gh auth login,npm login) open your Windows browser.
sudo apt install -y wslu
echo 'export BROWSER=wslview' >> ~/.bashrc # or ~/.zshrcThese need Windows interop, which is on by default. If you turned off the Windows PATH, use the full paths or the aliases from Call Windows apps without the Windows PATH.
Linux from Windows#
- Run a Linux command from PowerShell:
wsl -e htop,wsl --cd ~ -e pnpm dev, or simplywsl ls -la. - Linux GUI apps: WSLg runs apps like
gitkormeldas normal Windows windows (sudo apt install -y gitk meld).
Development#
- A public URL in one line:
cloudflared tunnel --url http://localhost:3000gives a temporary HTTPS address for webhooks and demos. Install withmise use -g cloudflared. Anyone with the URL reaches your dev server, so stop it when you’re done. - Throwaway distros:
wsl --install -d Debian, or import a backup under a new name (Back up and restore your WSL distro), to try risky setups away from your main environment.wsl --unregister Debiandeletes it and everything in it. - Containers in a terminal UI:
lazydockershows logs, stats and restarts with single keys (install it).
Shell history#
- Keep secrets out of history: start a line with a space. zsh (with
setopt HIST_IGNORE_SPACE) and atuin skip it.atuin search --delete "text"removes past entries. - See what you type most:
atuin stats.
Windows desktop#
- Snap windows: PowerToys FancyZones keeps terminal, editor and browser in fixed zones. PowerToys Command Palette opens on Win+Alt+Space.