In this article I want to share with you my macOS setup for web development.
- Mac Setup for Web Development [2024]
- MacBook Pro Specifications
- System Settings
- System Settings (Terminal)
- Homebrew
- iTerm2
- Shell configuration
- VS Code
- Sublime
- Git
- SSH
- OpenPGP
- Fast Node Manager (fnm) for Node.js
- Git project folder
- 16-inch
- Apple MacBook Pro, M2 Pro 12βCore CPU, 19βCore GPU and 16βCore Neural Engine
- 32 GB RAM
- 512 GB SSD
- QWERTY = English (USA)
- macOS Sonoma (14.2.1)
- Profile
- Set avatar
- iCloud
- Disable
- Network
- Firewall
- On
- Options: Enable stealth mode
- Firewall
- Notifications
- Off
- General
- Software Update: Update All
- AirDrop: No One
- Sharing
- Make sure everything is off
- Change computer name (local hostname)
- Time Machine: Configure when required
- Appearance
- Auto
- Accessibility
- Display
- Shake mouse pointer to locate: Off
- Display
- Control Centre
- Battery: Show Percentage
- Siri & Spotlight
- Disable
- Privacy & Security
- Analytics & Improvements: Off
- Apple advertising: Off
- Screen recording: Firefox
- FileVault: On
- Desktop & Dock
- Remove most applications from Dock
- Smaller Dock
- Minimise windows using: Scale Effect
- Magnification: Off
- Automatic Hide
- Show recent applications in Dock: Off
- Show indicators for open applications: On
- Click wallpaper to reveal desktop: Only in stage manager
- Stage manager: Off
- Hot Corners: Disable all
- Display
- True Tone: On
- Wallpaper
- Dynamic
- Lock Screen
- Start Screen Saver when inactive: Never
- Turn display off (battery): 5 minutes
- Turn display off (power): 10 minutes
- Require password: Immediately
- Touch ID & Password
- Enable RH-finger
- Enable LH-finger
- Game Center
- Disable
- Keyboard
- Key repeat rate: 10/10
- Delay until repeat: 10/10
- Keyboard Shortcuts
- Disable Launchpad & Dock
- Disable Mission control
- Disable Spotlight
- Disable Accessibility
- Text Input
- Edit
- Disable Correct spelling automatically
- Disable Capitalise word automatically
- Disable Add full stop with double-space
- Disable Use smart quotes and dashes
- Use
"
for double quotes - Use
'
for single quotes
- Edit
- Trackpad
- Point & Click
- Tap to Click
- Look up & data detectors: Off
- Speed: 4/10
- Scroll & Zoom
- Natural scrolling: Off
- More Gestures
- Notification centre: Off
- Mission Control: Off
- Launchpad: Off
- Show desktop: Off
- Point & Click
- Printers & Scanners
- Add printer/scanner when required
- Finder
- General
- New Finder: Desktop
- Hide all Tags
- Sidebar
- Enable
- AirDrop
- Applications
- Desktop
- Documents
- Downloads
- Pictures
- (Your account name)
- Disable
- iCloud folders
- Tags
- Enable
- Advanced
- Show all filename extensions
- Remove Items from Bin after 30 Days
- General
- Widget
- Remove widgets
- Storage
- Remove Garage Band & Sound Library
- Remove iMovie
- Desktop
- Right click > Sort By > Snap to Grid
Override more system settings from the terminal...
# change computer name
sudo scutil --set ComputerName "newname"
sudo scutil --set LocalHostName "newname"
sudo scutil --set HostName "newname"
# take screenshots as jpg (usually smaller size) and not png
defaults write com.apple.screencapture type jpg
# do not open previous previewed files (e.g. PDFs) when opening a new one
defaults write com.apple.Preview ApplePersistenceIgnoreState YES
# show Library folder
chflags nohidden ~/Library
# show hidden files
defaults write com.apple.finder AppleShowAllFiles YES
# show path bar
defaults write com.apple.finder ShowPathbar -bool true
# show status bar
defaults write com.apple.finder ShowStatusBar -bool true
# set dock animation speed to 600ms
defaults write com.apple.dock autohide-time-modifier -float 0.6;
# restart dock
killall Dock;
# restart finder
killall Finder;
Install Homebrew as package manager for macOS:
# paste in terminal and follow the instructions
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
Update everything in Homebrew to recent version:
brew update
Install GUI applications (read more about these in GUI Applications):
brew install --cask \
bitwarden \
alfred \
google-chrome \
firefox \
iterm2 \
visual-studio-code \
bruno \
github \
https://raw.githubusercontent.com/Homebrew/homebrew-cask/9c7cef6f712515f8b87983685f0e82047362e08c/Casks/sublime-text.rb \
spotify \
rectangle \
appcleaner \
slack \
discord \
vlc \
figma \
keyboardcleantool \
betterdisplay \
imageoptim \
handbrake \
the-unarchiver \
tunnelblick
Install terminal applications (read more about these in Terminal Applications):
brew install \
wget \
svgo \
git \
openssl \
pnpm \
commitizen
Optional: These are applications I like to use in my specific setup
brew install --cask \
yubico-authenticator \
logitech-options
- Bitwarden (password manager)
- Preferences
- Vault timeout: 5 minutes
- Clear clipboard: 30s
- Enable Touch ID
- Start automatically on login
- Theme: Dark
- Preferences
- Alfred (spotlight alternative)
- Use license
- Set shortcut to: option + space
- Launch Alfred at login
- Appearance
- Alfred macOS Dark
- Hide hat on Alfred window
- Google Chrome (web development)
- Never save passwords
- Chrome Extensions
- Firefox (web development, web browsing)
- Sync up with Mozilla account or manually import bookmarks
- Set default browser
- Never save passwords
- Firefox Extensions
- iTerm2 (terminal)
- Visual Studio Code (web development IDE)
- Bruno (api development platform)
- Preferences
- Font
- Code Editor Font: Hack Nerd Font Mono
- Theme
- Dark
- Font
- Preferences
- GitHub Desktop (GUI for Git)
- Preferences
- Intergrations
- External editor: Visual Studio Code
- Shell: iTerm2
- Appearance
- Enable dark mode
- Advanced
- Disable: Usage (Help GitHub Desktop improve by submitting)
- Intergrations
- Preferences
- Sublime Text (lightweight editor)
- Optional: Disable updates (my license is not valid for newer versions)
- Rectangle (window manager)
- Use Rectangle settings, not Spectacle
- Enable "Launch at Login"
- Appcleaner (app uninstaller)
- Slack (team messenger)
- Discord (community messenger)
- VLC (video player)
- Use as default for video files
- Figma (design)
- KeyboardCleanTool (blocks keyboard for cleaning)
- BetterDisplay (display tool)
- ImageOptim (performance)
- Handbrake (performance)
- The Unarchiver (unarchiver)
- Tunnelblick (vpn)
- wget (curl replacement)
- git (version control)
- openssl (OpenSSH)
- pnpm (node package manager)
- commitzen (committing rules for projects)
- Yubico Authenticator (TOTP manager)
- Logi Options (drivers and settings for Logitech products)
The look and feel we want to achieve from our terminal:
- Make iTerm2 Default Term
- Preferences ->
- General -> Window
- Unselect "Native full screen windows"
- Appearance ->
- Tabs
- Unselect "Show tab bar in fullscreen"
- Dimming
- Unselect all dimming and
- Set dimming amount: 1
- General
- Theme: minimal
- Tabs
- Profiles -> Window
- Transparency: 0
- Style: Normal
- Screen: Main Screen
- Columns: 120
- Rows: 30
- Profiles -> Advanced
- Semantic History -> Open with editor ... -> VS Code
- Advanced
- Tabs: in minimal tab outline 0.1
- General -> Window
Download the snazzy theme
bash (curl -Ls https://raw.githubusercontent.com/sindresorhus/iterm2-snazzy/main/Snazzy.itermcolors > /tmp/Snazzy.itermcolors && open /tmp/Snazzy.itermcolors)
Now you have to manually configure the iTerm2 color theme:
iTerm2 Preferences: Profiles > Colors > Color Presets: Snazzy
As font we will be using Hack Nerd Font in iTerm2, VS Code, and Sublime Text. Install it via:
brew tap homebrew/cask-fonts
brew install --cask font-hack-nerd-font
Use the new font in
iTerm2: Preferences -> Profile -> Text -> Font: font-hack-nerd-font.
By default macOS ships with Zsh, in my opinion it's still missing some important features and for that reason I like to extend it with some plugins and custom settings.
My personal favorite is the relatively new Fish shell, it's blazing fast and very easy to use. I will also provide you with instructions on how to get started with this shell.
Configure with Zsh
Install Oh My Zsh for an improved terminal experience:
sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"
Update everything (e.g. plugins) in Oh My Zsh to recent version:
omz update
Important: If you change something in your Zsh configuration (.zshrc), force a reload:
source ~/.zshrc
Install Starship as your new terminal theme:
brew install starship
Make it the default theme for Zsh by using the following command:
echo 'eval "$(starship init zsh)"' >> ~/.zshrc
If the theme and font changes do not apply, reload your zsh configuration or close/open iTerm2.
To get started configuring starship, create the following file: ~/.config/starship.toml
.
mkdir -p ~/.config && touch ~/.config/starship.toml
All configuration for starship is done in this TOML file:
# Get editor completions based on the config schema
"$schema" = 'https://starship.rs/config-schema.json'
# Add longer timeout for fnm to install node
command_timeout = 9000
These are my settings but feel free to add your own
Please follow the instructions and install these plugins by using Oh My Zsh:
Open vim to view the current configuration
vim ~/.zshrc
Copy and paste the new configuration but don't forget to replace the placeholders.
# Path to your oh-my-zsh installation.
export ZSH="$HOME/.oh-my-zsh"
# enable when using Yubikey, otherwise you can remove these lines
# export GPG_TTY=$(tty)
# export KEYID="<your gpg key>"
# enable when using GPG for SSL, otherwise you can remove these lines
# export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket)
# gpgconf --launch gpg-agent
# Git variables
export GH_TOKEN="<your token>"
export GIT_AUTHOR_NAME="<your name>"
export GIT_AUTHOR_EMAIL="<your email>"
export GIT_COMMITTER_NAME="<your name>"
export GIT_COMMITTER_EMAIL="<your email>"
# Which plugins would you like to load?
# Standard plugins can be found in $ZSH/plugins/
# Custom plugins may be added to $ZSH_CUSTOM/plugins/
# Example format: plugins=(rails git textmate ruby lighthouse)
# Add wisely, as too many plugins slow down shell startup.
plugins=(
git
zsh-completions
zsh-autosuggestions
zsh-syntax-highlighting
F-Sy-H
)
# get machine's ip address
alias ip="ipconfig getifaddr en0"
# get global ip address
alias pubip="curl ifconfig.me"
# edit global zsh configuration
alias zshconfig="vim ~/.zshrc"
# reload zsh configuration
alias zshsource="source ~/.zshrc"
# update brew and cleanup
alias brewup="brew update; brew upgrade; brew cleanup; brew doctor"
# open file or folder in Sublime Text
alias sublime='open -a "Sublime Text"'
# open file or folder in VSCode
alias code='open -a "Visual Studio Code"'
# load zsh-completions
autoload -U compinit && compinit
# use oh my zsh
source $ZSH/oh-my-zsh.sh
# use fnm
eval "$(fnm env --use-on-cd)"
# use starship theme (needs to be at the end)
eval "$(starship init zsh)"
Configure with Fish
To get started download the shell by using Homebrew:
brew install fish
Now we will configure it to be our default shell:
# Add the shell to /etc/shells with
echo /opt/homebrew/bin/fish | sudo tee -a /etc/shells
# changing the default shell to fish
chsh -s /opt/homebrew/bin/fish
Congratulations, you've now successfully installed the Fish shell on your local machine let's dive into the configurations.
Install Starship as your new terminal theme:
brew install starship
Make it the default theme for Fish by using the following command:
echo 'starship init fish | source' >> ~/.config/fish/config.fish
If the theme and font changes do not apply, reload your fish configuration or close/open iTerm2.
To get started configuring starship, create the following file: ~/.config/starship.toml
.
mkdir -p ~/.config && touch ~/.config/starship.toml
All configuration for starship is done in this TOML file:
# Get editor completions based on the config schema
"$schema" = 'https://starship.rs/config-schema.json'
# Add longer timeout for fnm to install node
command_timeout = 9000
These are my settings but feel free to add your own
To add and preserve variables in the fish shell its very easy to do. Let's add some variables that I use frequently, please remember to change the placeholders
# enable when using Yubikey
# set -Ux KEYID "<your gpg key>"
# Git variables
set -Ux GH_TOKEN <your token>
set -Ux GIT_AUTHOR_NAME <your name>
set -Ux GIT_AUTHOR_EMAIL <your email>
set -Ux GIT_COMMITTER_NAME <your name>
set -Ux GIT_COMMITTER_EMAIL <your email>
Universal variables will be stored in the file ~/.config/fish/fish_variables
.
To remove a variable you can use: set --erase myvar
or a function unset
that we will add later.
Open vim to view the current configuration
vim ~/.config/fish/config.fish
Copy and paste the new configuration
if status is-interactive
# Commands to run in interactive sessions can go here
end
# get machine's ip address
alias ip="ipconfig getifaddr en0"
# get global ip address
alias pubip="curl ifconfig.me"
# edit global fish configuration
alias fconfig="vim ~/.config/fish/config.fish"
# reload zsh configuration
alias fsource="source ~/.config/fish/config.fish"
# update brew and cleanup
alias brewup="brew update; brew upgrade; brew cleanup; brew doctor"
# open file or folder in Sublime Text
alias sublime='open -a "Sublime Text"'
# open file or folder in VSCode
alias code='open -a "Visual Studio Code"'
# add fish path for homebrew
fish_add_path /opt/homebrew/bin
# use starship theme (needs to be at the end)
starship init fish | source
Install the package with homebrew:
brew install fnm
Create ~/.config/fish/conf.d/fnm.fish
add this line to it:
fnm env --use-on-cd | source
Create ~/.config/fish/conf.d/gnupg.fish
add these lines to it:
# Ensure that GPG Agent is used as the SSH agent
set -e SSH_AUTH_SOCK
set -U -x SSH_AUTH_SOCK (gpgconf --list-dirs agent-ssh-socket)
set -x GPG_TTY (tty)
gpgconf --launch gpg-agent
Just like with Zsh, you can use functions to extend the basic terminal commands.
Here are some of my favorite functions that I use daily, you can copy and paste them into your Fish shell to add them.
alias for 'set --erease myvar'
function unset
set --erase $argv
end
funcsave unset
loads .env files into your terminal
function envsource
for line in (cat $argv | grep -v '^#' | grep -v '^\s*$')
set item (string split -m 1 '=' $line)
set -gx $item[1] $item[2]
echo "Exported key $item[1]"
end
end
funcsave envsource
decrypt a gpg file with my private key
function gpg-decrypt
set -l output $argv[1]
gpg --decrypt --armor $output
end
funcsave gpg-decrypt
encrypt a gpg file with my public key
function gpg-encrypt
set -l keyid $argv[1]
set -l output $argv[2]
gpg --encrypt --armor --recipient $keyid -o $output -
end
funcsave gpg-encrypt
If you ever want to reset your shell to the default settings, you can do so by running the following command:
chsh -s /bin/zsh
If you need to determine the path to your shell, you can use the following command:
which zsh fish
The look and feel we want to achieve from our IDE:
- Auto Close Tag
- Auto Rename Tag
- Better Comments
- Color Highlight
- Convert px to rem
- EditorConfig for VS Code
- ES7+ React/Redux/React-Native snippets
- ESLint
- Git Blame
- Git Graph
- GitHub Copilot
- GraphQL
- Highlight Matching Tag
- HTML CSS Support
- HTMLHint
- Import Cost
- Markdown All in One
- Material Icon Theme
- MDX
- One Dark Pro
- Paste JSON as Code
- Path Intellisense
- Polacode
- Prettier
- Tailwind CSS IntelliSense
- VSCode React Refactor
{
"workbench.colorTheme": "One Dark Pro",
"workbench.iconTheme": "material-icon-theme",
"workbench.sideBar.location": "left",
"workbench.startupEditor": "none",
"workbench.statusBar.visible": true,
"workbench.editor.enablePreview": true,
"workbench.activityBar.visible": true,
"workbench.editor.restoreViewState": true,
"editor.fontFamily": "Hack Nerd Font Mono",
"editor.lineHeight": 1.6,
"editor.tabSize": 2,
"editor.insertSpaces": false,
"editor.detectIndentation": false,
"editor.renderWhitespace": "none",
"editor.scrollBeyondLastLine": true,
"editor.minimap.enabled": false,
"editor.lineNumbers": "on",
"editor.find.seedSearchStringFromSelection": "never",
"editor.renderLineHighlight": "all",
"editor.inlineSuggest.enabled": true,
"editor.quickSuggestions": {
"strings": true
},
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true,
"editor.formatOnType": false,
"editor.formatOnPaste": false,
"editor.codeActionsOnSave": {
"source.fixAll": true,
"source.sortImports": true
},
"workbench.colorCustomizations": {
"editor.lineHighlightBackground": "#223851"
},
"files.trimFinalNewlines": true,
"files.trimTrailingWhitespace": true,
"files.associations": {
".env*": "makefile"
},
"tailwindCSS.experimental.classRegex": [
["cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"]
],
"eslint.validate": [
"javascript",
"javascriptreact",
"typescript",
"typescriptreact"
],
"javascript.validate.enable": false,
"javascript.updateImportsOnFileMove.enabled": "never",
"typescript.updateImportsOnFileMove.enabled": "never",
"explorer.confirmDelete": false,
"explorer.compactFolders": false,
"explorer.confirmDragAndDrop": false,
"js/ts.implicitProjectConfig.checkJs": true,
"extensions.ignoreRecommendations": true,
"security.workspace.trust.untrustedFiles": "open",
"git.openRepositoryInParentFolders": "never",
"typescript.preferences.quoteStyle": "double",
"javascript.preferences.quoteStyle": "double",
"github.copilot.enable": {
"*": true,
"plaintext": true,
"markdown": true,
"scminput": false
}
}
Not used for web development anymore. Primarily used for quick edits
- Use license
- Agila Theme (Theme)
- Predawn (Theme)
- SideBarEnhancements (Folder/File Features)
- TrailingSpaces (Deletes Trailing Spaces)
{
"caret_style": "solid",
"folder_exclude_patterns":
[
".git",
"node_modules"
],
"font_size": 13,
"font_face": "Hack Nerd Font",
"gutter": true,
"highlight_line": true,
"highlight_modified_tabs": true,
"ignored_packages":
[
"TypeScript",
"Vintage"
],
"line_padding_bottom": 1,
"line_padding_top": 1,
"predawn_findreplace_small": true,
"predawn_sidebar_arrows": true,
"predawn_sidebar_narrow": true,
"predawn_sidebar_xsmall": true,
"predawn_tabs_small": true,
"rulers":
[
120
],
"scroll_past_end": true,
"show_line_numbers": true,
"spell_check": false,
"tab_size": 2,
"theme": "Agila Origin.sublime-theme",
"theme_agila_compact_sidebar": true,
"theme_agila_compact_tab": true,
"theme_agila_horizontal_scrollbar_thinnest": true,
"theme_agila_sidebar_font_xsmall": true,
"theme_agila_sidebar_mini": true,
"theme_agila_vertical_scrollbar_thinnest": true,
"translate_tabs_to_spaces": false,
"trim_trailing_white_space_on_save": true,
"color_scheme": "Packages/Agila Theme/Agila Origin Oceanic Next.tmTheme",
"update_check": false,
}
From terminal, set global name and email:
git config --global user.name "Your Name"
git config --global user.email "[email protected]"
git config --global core.ignorecase false
Improved git log
git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"
Set the default branch to main instead of master
git config --global init.defaultBranch main
Print global git configuration:
git config --list
There are several strategies for SSH keys: one SSH key to rule them all or one SSH key per service. I use the latter one and will here run you through it by connecting to GitHub via SSH.
First, create a new SSH key in the ~/.ssh folder:
# in case the folder is not there yet
mkdir ~/.ssh
cd ~/.ssh
ssh-keygen -t ed25519 -C "github"
# follow instructions
# use file name: github
# use passphrase and store it somewhere secure
Confirm whether passphrase was used properly by accessing private key:
ssh-keygen -y -f github
# confirm with passphrase
Create the SSH configuration file if it doesn't exist yet:
touch ~/.ssh/config
# in case the file is not there yet
In your ~/.ssh/config file, add the new SSH key, so that it can get picked up for every terminal session automatically:
Host *
AddKeysToAgent yes
UseKeychain yes
IdentityFile ~/.ssh/github
Add SSH key to MacOS' keychain:
ssh-add --apple-use-keychain ~/.ssh/github
Add the public key manually to your GitHub settings via the website:
cat ~/.ssh/github.pub | pbcopy
# copy public key to clipboard and add it manually to https://github.com/settings/keys
That's it. You have created an SSH key locally, secured it via a passphrase, made it automatically available for every terminal session, and applied it to GitHub. In the case of GitHub, you are now able to interact with GitHub via SSH.
With OpenPGP, you can sign your commits on GitHub. This is of course not mandatory but a good practice especially when you are using multiple computers. There are multiple ways to setup OpenPGP on your computer, my recommendation is to use a Yubikey and follow this guide to add your keys.
Let's start by installing all of the dependencies:
brew install \
ykman \
gnupg \
pinentry-mac
Now assuming you already have the keys set up, you can import the (public) key(s) like this:
# import OpenPGP key
gpg --import ./public.asc
Now check if you have imported all of your keys by using:
# View imported keys on your machine
gpg -k
Copy your public key ID
to the clipboard, we will need this later to configure Git.
Let's first add the pin-prompts to your terminal + macOS
# add pin-prompt to cli you might want to add this to your shell configuration
export GPG_TTY=$(tty)
# add pinnetry-mac to your gpg config
echo "pinentry-program /opt/homebrew/bin/pinentry-mac" > ~/.gnupg/gpg-agent.conf
# restart the agent
killall gpg-agent
Almost done, now we just have to configure Git by letting it automatically sign the commits and tags and use our public key ID
.
# tell git config to sign all commits and tags by default (alternative is -s flag)
git config --global commit.gpgsign true
git config --global tag.gpgsign true
# configure the signature key
git config --global user.signingkey <PUBLIC KEY ID>
A very cool feature of OpenPGP is that you use it for SSH authentication. In combination with a YubiKey, you will always carry a physical key that allows you to access your Git repositories. Here are two methods of enabling SSH authentication:
That's it OpenPGP is now configured on your machine, if you like to learn more about how to create these OpenPGP keys I can recommend reading one of these guides:
- About commit signature verification with Github
- Yubikey guide (OpenPGP)
- Yubikey guide alternative (OpenPGP)
One final note, if you're using a Yubikey for signing commits on your brand new machine you will need to run this command to reset the default key location:
gpg-connect-agent "scd serialno" "learn --force" /bye
The Fast Node Manager (fnm) is used to install and manage multiple Node versions. The idea and CLI is identical to nvm
it's just faster basically.
Let's start by installing fnm on your local machine:
brew install fnm
Now configure your terminal to use fnm by following these instructions
Now let's install the lts version of Node.js on the machine
fnm install --lts
Afterward, check whether the installation was successful and whether the node package manager (npm) got installed along the way:
node -v && npm -v
And set defaults for npm:
npm set init-author-email "[email protected]"
npm set init-author-name "example_user"
npm set init-license "MIT"
That's it. If you want to list all your Node.js installations, type the following:
fnm list
If you want to install a newer Node.js version, then type:
fnm install <version> && fnm use <version>
Optionally install yarn if you use it as alternative to npm:
npm install -g yarn
yarn -v
If you want to list all globally installed packages, run this command:
npm list -g --depth=0
That's it. You have a running version of Node.js and its package manager.
To keep your mac clean, I suggest adding a new (root) folder for all of your git projects
mkdir ~/Git
Drag this folder to your favorites in the Finder and configure your terminal to open this location by default
I hope my setup helps other developers to get their Mac up and running. If you have any additional ideas or want to share your setup, let me know!
This article is inspired by Robin Wieruch.