Most dev environments accumulate. A plugin here, a config there, a version manager someone on Stack Overflow recommended in 2019. The result is a shell that takes 800ms to start and a workflow full of friction you've stopped noticing.

This guide sets up a fast, opinionated baseline. Everything here is a decision, not a suggestion.

Prerequisites

  • macOS or Linux

  • Homebrew on macOS (/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)")

  • A terminal and basic comfort editing text files

The shell

zsh is the default on macOS since Catalina. On Linux:

sudo apt install zsh        # Debian/Ubuntu
sudo dnf install zsh        # Fedora/RHEL
chsh -s $(which zsh)        # Set as default, then restart terminal

Verify it took:

echo $SHELL
# /bin/zsh or /usr/bin/zsh

Plugins

Two plugins worth installing — nothing else. Clone them:

mkdir -p ~/.zsh
git clone https://github.com/zsh-users/zsh-autosuggestions ~/.zsh/zsh-autosuggestions
git clone https://github.com/zsh-users/zsh-syntax-highlighting ~/.zsh/zsh-syntax-highlighting

Open ~/.zshrc (create it if it doesn't exist):

nano ~/.zshrc

Add these two lines:

source ~/.zsh/zsh-autosuggestions/zsh-autosuggestions.zsh
source ~/.zsh/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh

Save and reload:

source ~/.zshrc

What changes: commands from your history appear as greyed-out suggestions while you type — hit to accept. Invalid commands turn red before you run them. Both save more time than they look like they will.

Skip oh-my-zsh. It's slow, loads things you don't need, and makes your config someone else's problem.

The prompt

Starship replaces the default shell prompt with one that shows git branch, dirty state, active language version, and last command exit status — in under 5ms.

Install

# macOS
brew install starship

# Linux or macOS alternative
curl -sS https://starship.rs/install.sh | sh

Configure

Open ~/.zshrc:

nano ~/.zshrc

Add this line at the very end of the file:

eval "$(starship init zsh)"

Reload:

source ~/.zshrc

Your prompt updates immediately. The default config works well out of the box. When you're ready to customize — colours, which segments show, order — config lives in ~/.config/starship.toml. Full reference here.

Language versions

Don't install Node, Python, or Ruby globally. Use mise — one tool that replaces nvm, pyenv, rbenv, and asdf.

Install

brew install mise

Configure

Open ~/.zshrc:

nano ~/.zshrc

Add:

eval "$(mise activate zsh)"

Reload:

source ~/.zshrc

Per-project versions

In each project root, create .mise.toml:

[tools]
node = "20"
python = "3.12"

Then run once:

mise install

The right version activates automatically when you cd into the project. No more nvm use at the start of every session. Full docs.

The editor

VS Code if you want something that works immediately. Neovim if you're willing to invest a week for a tool you'll use for a decade.

Pick one. Using both is just avoiding the decision.

For VS Code, three extensions that earn their place:

  • Error Lens — shows errors on the line they occur, not buried in a separate panel

  • GitLens — inline blame, history, and diff without leaving the file

  • Prettier — formats on save, eliminates style arguments entirely

To enable format on save, open VS Code settings (Cmd+, on macOS), search formatOnSave, and check the box. Or add directly to settings.json:

{
  "editor.formatOnSave": true
}

Git

The config most engineers never set up:

nano ~/.gitconfig
[alias]
  co = checkout
  st = status -sb
  lg = log --oneline --graph --decorate --all
  undo = reset HEAD~1 --mixed

[push]
  default = current

[pull]
  rebase = true

[core]
  autocrlf = input

What each setting does:

  • git lg — branch graph in the terminal, no GUI needed

  • push.default = current — no more --set-upstream on every new branch

  • pull.rebase = true — keeps history linear without thinking about it

  • undo — rolls back the last commit without losing your changes

Reload is automatic — .gitconfig is read fresh on each git command.

Aliases

Add to ~/.zshrc:

# Navigation
alias ..='cd ..'
alias ...='cd ../..'

# Safer defaults (prompts before overwriting)
alias cp='cp -i'
alias mv='mv -i'
alias rm='rm -i'

# Reload config without opening a new shell
alias reload='source ~/.zshrc'

# Common tools
alias dc='docker compose'
alias k='kubectl'

Run source ~/.zshrc after saving. Rule: alias things you type three times a day. Not things you type once a month.

Dotfiles

The setup above spans several files across your home directory. Put them all in a git repo and symlink them back.

mkdir ~/dotfiles
# Move configs in, then symlink:
ln -s ~/dotfiles/.zshrc ~/.zshrc
ln -s ~/dotfiles/.gitconfig ~/.gitconfig

New machine setup becomes: clone the repo, run the symlink script. chezmoi handles this with templating if your setup varies across machines. A plain shell script works just as well if it doesn't.

A dev environment that fights you is a tax on every working hour. Set this up once.

Keep reading