mac setup guide for web development

Cover Image for mac setup guide for web development
David Viramontes
David Viramontes

-- As of this writing, I can confirm that all of these tools work on M1+ and intel based macs.

After going through this setup on multiple machines over the years, I’m finally taking the time to write it down and I'll try to update it as my workflow and technology preferences change. Most of these steps and tools are very personal to me and how I like to work but you might find gems for yourself.


  • MacOS Monterrey or newer
  • Package management with homebrew. I’ll do a separate post on nix one day 🤞🏽
  • iterm2 + zsh
  • doom emacs. No strong opinions here, just less heavy than spacemacs
  • (caveat: I don’t use emacs regularly, but I learned some of the most useful keybindings so I’m stuck with it for now).
  • node.js via NVM, better version management for node.js
  • fzd as fuzzy finder
  • Rectangle as window manager
  • Clippy as copy / paste buffer extension tool


via package manager

# window manager
brew install --cask rectangle

# increase your paste buffer stack length from 1 to n
brew install --cask clipy

brew install --cask visual-studio-code
# github sign-in to sync settings


Breaking these up into individual commands helps with some of the setup after (as suppose to doing a big brew install x y z).

brew install emacs

brew install nvm
# after
export NVM_DIR="$HOME/.nvm"
[ -s "/usr/local/opt/nvm/" ] && . "/usr/local/opt/nvm/"  # This loads nvm
[ -s "/usr/local/opt/nvm/etc/bash_completion.d/nvm" ] && . "/usr/local/opt/nvm/etc/bash_completion.d/nvm"

brew install fzf
# after
[ -f ~/.fzf.zsh ] && source ~/.fzf.zsh

brew install z
# after
. /usr/local/etc/profile.d/

brew install direnv
# after
eval "$(direnv hook zsh)"

Environment Variables

Direnv is a great way to keep your environment variables relatively close to the project that needs them. Example from project page:

# Create a new .envrc. This file is bash code that is going to be loaded by
# direnv.
$ echo export FOO=foo > .envrc
.envrc is not allowed

# allow it
$ direnv allow .
direnv: reloading
direnv: loading .envrc
direnv export: +FOO

# Show that the FOO environment variable is loaded.
$ echo ${FOO-nope}

# Exit the project
$ cd ..
direnv: unloading

# And now FOO is unset again
$ echo ${FOO-nope}

Terminal PS1 Decorator

  • p10k is all i need these days, it is nice, concise and easy to setup.
echo $PS1

Terminal Navigation


Fuzzy finding is an absolute must these days as the command line args for different languages are getting increasingly complex. I'm looking at you Clojure! with stuff like clj -A:dev -M -m :angry-fist-emoji:. Use ctrl + r to engage fuzzy finding.


I use z frequently to jump between different directories. It works by building up a small database based on how frequently you visit those directories. Once it's learned enough about your project, it can become quite easy for z to know where you wanna go next.

❯ z -l
0.255153   /Users/dav/foo
0.268972   /Users/dav/bar
0.276813   /Users/dav/war

next time you wanna go to a directory, all you have to do is

z foo
-> /Users/dav/foo

Iterm2 key preferences

In iterm, go to profiles > keys > key mappings and select Natural text editing. This makes it so that you can use arrow keys in terminal navigation and a bunch of other useful keybindings come with it.

Bash Functions

function gitinit(){
    git init && git add . -v && git commit -am 'init'

function masterToMain(){
    git branch -m master main
    git fetch origin
    git branch -u origin/main main
    git remote set-head origin -a


For "silky smooth hopping" ;)

$ cat <<EOF > ~/.ssh/config
Host kimchitaco
  User root
  IdentityFile ~/.ssh/id_rsa

now everytime you wanna hop to all you have to do is ssh kimchitaco

Git Config

$ cat <<EOF > ~/.gitconfig
	name = David A. Viramontes
	email = <email>
	ui = true
	editor = emacs
	excludesfile = /Users/$HOME/.gitignore_global
	co = checkout
	cm = commit
	s  = status
	b  = branch
	up = push origin HEAD
	cp = cherry-pick
	hist = log --pretty=format:\"%h %ad | %s%d [%an]\" --graph --date=short
	defaultBranch = main
	ff = true
	helper = store

Global Gitignore

$ cat <<EOF > ~/.gitignore_global

Takes effect after running:

git config --global core.excludesfile ~/.gitignore_global


After 1.8 this became much easier.

  • mkdir ~/go

And then add this to your ~/.zshrc

export GOPATH=$HOME/go
export GOBIN=$GOPATH/bin


go env GOBIN
go env GOPATH

Elixir & Erlang

Other ways to get erlang and elixir into your system are more convenient but this is the setup i've found to be most reliable

  • install adsf
  • Add plugins
    • asdf plugin add erlang
    • asdf plugin-add elixir
  • asdf install erlang 25.0.3
  • asdf install elixir 1.14.0-rc.0-otp-25
  • asdf global erlang 25.0.3
  • asdf global elixir 1.14.0
  • asdf reshim
  • add shims bin to path
    • export PATH="$HOME/.asdf/shims:$PATH"


alias zshedit="emacs ~/.zshrc"
alias ll="ls -lh"

That's it for now. I'll update this post as I go, so check back!