My Development Setup: Tools and Configurations
After 5 years of constantly tweaking my development environment, I've finally reached a setup that I haven't changed in 8 months. That's a record for me. This configuration saves me roughly 2 hours per day and has measurably increased my productivity by 40%.
The secret isn't having the most tools—it's having the right tools configured perfectly for your workflow. Today, I'll share my complete setup, including the exact configurations, automations, and lesser-known tools that transformed how I work.
The Hardware Foundation
Before diving into software, here's the hardware that powers everything:
# hardware-specs.yml
primary_machine:
model: "MacBook Pro 16-inch (2024)"
chip: "M4 Pro"
memory: "32GB"
storage: "1TB SSD"
reasoning: "M4 handles Docker, multiple IDEs, and large builds without throttling"
peripherals:
monitor: "LG 32UL950-W 32-inch 4K"
keyboard: "Keychron K8 (hot-swappable switches)"
mouse: "Logitech MX Master 3S"
headphones: "Sony WH-1000XM5"
workspace:
desk: "Standing desk (Jarvis Bamboo 72x30)"
lighting: "BenQ ScreenBar Halo"
organization: "Cable management tray + wireless charging pad"
The 32GB RAM was crucial for my workflow. I regularly run:
- 5-10 Docker containers
- Multiple VS Code instances
- Chrome with 50+ tabs
- Terminal with 20+ sessions
- Design tools (Figma desktop app)
VS Code: The Perfectly Tuned IDE
Extensions That Actually Matter
After trying 200+ extensions, these 15 are the only ones I keep:
// .vscode/extensions.json
{
"recommendations": [
// Core productivity
"ms-vscode.vscode-typescript-next",
"esbenp.prettier-vscode",
"bradlc.vscode-tailwindcss",
"formulahendry.auto-rename-tag",
"christian-kohler.path-intellisense",
// Git integration
"eamodio.gitlens",
"github.vscode-pull-request-github",
// Development experience
"ms-vscode.vscode-json",
"ms-vscode-remote.remote-containers",
"ms-playwright.playwright",
// AI assistance
"github.copilot",
"github.copilot-chat",
// Themes and appearance
"pkief.material-icon-theme",
"dracula-theme.theme-dracula"
]
}
My VS Code Configuration
Here's my complete settings.json
that took 3 years to perfect:
{
// Editor behavior
"editor.fontSize": 14,
"editor.fontFamily": "JetBrains Mono, Monaco, 'Courier New', monospace",
"editor.lineHeight": 1.6,
"editor.fontLigatures": true,
"editor.tabSize": 2,
"editor.insertSpaces": true,
"editor.wordWrap": "on",
"editor.rulers": [80, 120],
// Auto-save and formatting
"files.autoSave": "onFocusChange",
"editor.formatOnSave": true,
"editor.formatOnPaste": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true,
"source.organizeImports": true
},
// Workspace efficiency
"workbench.editor.enablePreview": false,
"workbench.editor.closeOnFileDelete": true,
"workbench.startupEditor": "newUntitledFile",
"explorer.confirmDelete": false,
"explorer.confirmDragAndDrop": false,
// Terminal integration
"terminal.integrated.defaultProfile.osx": "zsh",
"terminal.integrated.fontSize": 13,
"terminal.integrated.cursorBlinking": true,
"terminal.integrated.commandsToSkipShell": [
"language-julia.interrupt"
],
// File associations and search
"files.associations": {
"*.mdx": "markdown",
".env*": "properties"
},
"search.exclude": {
"**/node_modules": true,
"**/dist": true,
"**/.next": true,
"**/coverage": true
},
// TypeScript and JavaScript
"typescript.updateImportsOnFileMove.enabled": "always",
"typescript.suggest.autoImports": true,
"javascript.updateImportsOnFileMove.enabled": "always",
// Git integration
"git.autofetch": true,
"git.confirmSync": false,
"git.enableSmartCommit": true,
"gitlens.hovers.currentLine.over": "line",
"gitlens.currentLine.enabled": false,
// Tailwind CSS
"tailwindCSS.includeLanguages": {
"typescript": "javascript",
"typescriptreact": "javascript"
},
"tailwindCSS.experimental.classRegex": [
["cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"],
["cx\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)"]
],
// Prettier configuration
"prettier.semi": true,
"prettier.singleQuote": true,
"prettier.tabWidth": 2,
"prettier.trailingComma": "es5",
// Theme and icons
"workbench.colorTheme": "Dracula",
"workbench.iconTheme": "material-icon-theme",
// Performance optimizations
"files.watcherExclude": {
"**/.git/objects/**": true,
"**/.git/subtree-cache/**": true,
"**/node_modules/**": true,
"**/dist/**": true,
"**/.next/**": true
}
}
Custom Keybindings
These keyboard shortcuts save me hundreds of keystrokes daily:
// keybindings.json
[
{
"key": "cmd+shift+e",
"command": "workbench.view.explorer",
"when": "viewContainer.workbench.view.explorer.enabled"
},
{
"key": "cmd+shift+f",
"command": "workbench.view.search",
"when": "viewContainer.workbench.view.search.enabled"
},
{
"key": "cmd+shift+g",
"command": "workbench.view.scm",
"when": "workbench.scm.active"
},
{
"key": "cmd+shift+d",
"command": "workbench.view.debug",
"when": "viewContainer.workbench.view.debug.enabled"
},
{
"key": "cmd+shift+x",
"command": "workbench.view.extensions",
"when": "viewContainer.workbench.view.extensions.enabled"
},
{
"key": "cmd+t",
"command": "workbench.action.terminal.toggleTerminal"
},
{
"key": "cmd+shift+t",
"command": "workbench.action.terminal.new"
},
{
"key": "cmd+w",
"command": "workbench.action.closeActiveEditor"
},
{
"key": "cmd+shift+w",
"command": "workbench.action.closeAllEditors"
}
]
Terminal Setup: The Command Center
iTerm2 Configuration
My iTerm2 profile for maximum productivity:
# ~/.iterm2_shell_integration.zsh
# Enable advanced features
test -e "${HOME}/.iterm2_shell_integration.zsh" && source "${HOME}/.iterm2_shell_integration.zsh"
# Split pane shortcuts
bind-key v split-window -h
bind-key s split-window -v
# Pane navigation
bind-key h select-pane -L
bind-key j select-pane -D
bind-key k select-pane -U
bind-key l select-pane -R
# Color scheme: Dracula
# Profile -> Colors -> Color Presets -> Dracula
Zsh with Oh My Zsh
Here's my complete .zshrc
configuration:
# ~/.zshrc
export ZSH="$HOME/.oh-my-zsh"
# Theme
ZSH_THEME="spaceship"
# Plugins for productivity
plugins=(
git
node
npm
yarn
docker
docker-compose
vscode
zsh-autosuggestions
zsh-syntax-highlighting
z
)
source $ZSH/oh-my-zsh.sh
# Custom aliases
alias ll="ls -alF"
alias la="ls -A"
alias l="ls -CF"
# Git aliases
alias gs="git status"
alias ga="git add"
alias gc="git commit"
alias gp="git push"
alias gl="git pull"
alias gd="git diff"
alias gco="git checkout"
alias gb="git branch"
alias glog="git log --oneline --decorate --graph"
# Development aliases
alias ns="npm start"
alias ni="npm install"
alias nid="npm install --save-dev"
alias nig="npm install --global"
alias nt="npm test"
alias nr="npm run"
# Docker aliases
alias d="docker"
alias dc="docker-compose"
alias dcu="docker-compose up"
alias dcd="docker-compose down"
alias dps="docker ps"
alias di="docker images"
# Directory navigation
alias ..="cd .."
alias ...="cd ../.."
alias ....="cd ../../.."
alias ~="cd ~"
alias -- -="cd -"
# Utility aliases
alias grep="grep --color=auto"
alias fgref="grep -r --include='*.js' --include='*.ts' --include='*.tsx'"
alias myip="curl ipinfo.io/ip"
alias weather="curl wttr.in"
# Project shortcuts
alias projects="cd ~/Projects"
alias blog="cd ~/Projects/mikul.me"
alias dotfiles="cd ~/dotfiles"
# Functions
mkcd() { mkdir -p "$1" && cd "$1"; }
extract() {
if [ -f $1 ]; then
case $1 in
*.tar.bz2) tar xjf $1 ;;
*.tar.gz) tar xzf $1 ;;
*.bz2) bunzip2 $1 ;;
*.rar) unrar e $1 ;;
*.gz) gunzip $1 ;;
*.tar) tar xf $1 ;;
*.tbz2) tar xjf $1 ;;
*.tgz) tar xzf $1 ;;
*.zip) unzip $1 ;;
*.Z) uncompress $1 ;;
*.7z) 7z x $1 ;;
*) echo "'$1' cannot be extracted via extract()" ;;
esac
else
echo "'$1' is not a valid file"
fi
}
# Environment variables
export EDITOR="code"
export BROWSER="google chrome"
export NODE_OPTIONS="--max-old-space-size=4096"
# Path modifications
export PATH="$HOME/.local/bin:$PATH"
export PATH="/opt/homebrew/bin:$PATH"
# Node.js version management
export NVM_DIR="$HOME/.nvm"
[ -s "/opt/homebrew/opt/nvm/nvm.sh" ] && \. "/opt/homebrew/opt/nvm/nvm.sh"
[ -s "/opt/homebrew/opt/nvm/etc/bash_completion.d/nvm" ] && \. "/opt/homebrew/opt/nvm/etc/bash_completion.d/nvm"
# Auto-load .nvmrc files
autoload -U add-zsh-hook
load-nvmrc() {
local node_version="$(nvm version)"
local nvmrc_path="$(nvm_find_nvmrc)"
if [ -n "$nvmrc_path" ]; then
local nvmrc_node_version=$(nvm version "$(cat "${nvmrc_path}")")
if [ "$nvmrc_node_version" = "N/A" ]; then
nvm install
elif [ "$nvmrc_node_version" != "$node_version" ]; then
nvm use
fi
elif [ "$node_version" != "$(nvm version default)" ]; then
echo "Reverting to nvm default version"
nvm use default
fi
}
add-zsh-hook chpwd load-nvmrc
load-nvmrc
Starship Prompt
My Starship configuration for a clean, informative prompt:
# ~/.config/starship.toml
format = """
[](#9A348E)\
$username\
[](bg:#DA627D fg:#9A348E)\
$directory\
[](fg:#DA627D bg:#FCA17D)\
$git_branch\
$git_status\
[](fg:#FCA17D bg:#86BBD8)\
$nodejs\
$rust\
$golang\
$php\
[](fg:#86BBD8 bg:#06969A)\
$docker_context\
[](fg:#06969A bg:#33658A)\
$time\
[ ](fg:#33658A)\
"""
[username]
show_always = true
style_user = "bg:#9A348E"
style_root = "bg:#9A348E"
format = '[$user ]($style)'
disabled = false
[directory]
style = "bg:#DA627D"
format = "[ $path ]($style)"
truncation_length = 3
truncation_symbol = "…/"
[git_branch]
symbol = ""
style = "bg:#FCA17D"
format = '[ $symbol $branch ]($style)'
[git_status]
style = "bg:#FCA17D"
format = '[$all_status$ahead_behind ]($style)'
[nodejs]
symbol = ""
style = "bg:#86BBD8"
format = '[ $symbol ($version) ]($style)'
[docker_context]
symbol = ""
style = "bg:#06969A"
format = '[ $symbol $context ]($style)'
only_with_files = false
[time]
disabled = false
time_format = "%R"
style = "bg:#33658A"
format = '[ ♥ $time ]($style)'
Git Configuration: Optimized for Speed
My complete .gitconfig
with aliases that save hours:
[user]
name = Mikul Gohil
email = hello@mikul.me
signingkey = [GPG_KEY_ID]
[core]
editor = code --wait
autocrlf = false
safecrlf = false
excludesfile = ~/.gitignore_global
pager = delta
[init]
defaultBranch = main
[push]
default = simple
autoSetupRemote = true
[pull]
rebase = false
[merge]
tool = vscode
[mergetool "vscode"]
cmd = code --wait $MERGED
[diff]
tool = vscode
colorMoved = default
[difftool "vscode"]
cmd = code --wait --diff $LOCAL $REMOTE
[alias]
# Basic shortcuts
a = add
aa = add --all
ap = add --patch
b = branch
ba = branch --all
bd = branch --delete
c = commit
ca = commit --amend
cm = commit --message
co = checkout
cob = checkout -b
d = diff
dc = diff --cached
f = fetch
fo = fetch origin
l = log --oneline
lg = log --oneline --decorate --graph
lga = log --oneline --decorate --graph --all
m = merge
p = push
pf = push --force-with-lease
pl = pull
r = reset
rb = rebase
rbi = rebase --interactive
rbc = rebase --continue
rba = rebase --abort
rs = reset --soft
rh = reset --hard
s = status --short --branch
st = status
# Advanced workflows
unstage = reset HEAD --
uncommit = reset --soft HEAD~1
recommit = commit --amend --no-edit
# Branch management
recent = branch --sort=-committerdate
gone = ! git for-each-ref --format='%(refname:short) %(upstream:track)' | awk '$2 == \"[gone]\" {print $1}' | xargs -r git branch -D
# Stash shortcuts
sl = stash list
ss = stash save
sp = stash pop
sd = stash drop
# Log formatting
hist = log --pretty=format:'%C(yellow)%h%C(reset) %C(green)%ad%C(reset) | %C(white)%s%C(cyan) [%an]%C(reset)%C(yellow)%d%C(reset)' --graph --date=short
today = log --since='1 day ago' --oneline --author='Mikul Gohil'
yesterday = log --since='2 days ago' --until='1 day ago' --oneline --author='Mikul Gohil'
[filter "lfs"]
clean = git-lfs clean -- %f
smudge = git-lfs smudge -- %f
process = git-lfs filter-process
required = true
[delta]
navigate = true
light = false
side-by-side = true
[interactive]
diffFilter = delta --color-only
Package Management and Node.js
Homebrew Setup
My essential Homebrew packages:
#!/bin/bash
# install-homebrew-packages.sh
# Taps
brew tap homebrew/cask-fonts
brew tap homebrew/cask-versions
# CLI Tools
brew install git
brew install node
brew install nvm
brew install yarn
brew install pnpm
brew install docker
brew install docker-compose
brew install gh
brew install jq
brew install tree
brew install htop
brew install wget
brew install curl
brew install ripgrep
brew install fd
brew install bat
brew install exa
brew install delta
brew install starship
brew install z
# GUI Applications
brew install --cask iterm2
brew install --cask visual-studio-code
brew install --cask google-chrome
brew install --cask brave-browser
brew install --cask figma
brew install --cask docker
brew install --cask postman
brew install --cask raycast
brew install --cask rectangle
brew install --cask cleanmaster- mac
brew install --cask 1password
brew install --cask spotify
brew install --cask discord
brew install --cask zoom
# Fonts
brew install --cask font-jetbrains-mono
brew install --cask font-fira-code
brew install --cask font-cascadia-code
Node.js Version Management
I use nvm with automatic version switching:
# ~/.nvmrc (project-specific)
18.18.0
# Auto-installation script
#!/bin/bash
# install-node-versions.sh
# Install and use Node.js versions
nvm install 16.20.0
nvm install 18.18.0
nvm install 20.8.0
# Set default
nvm alias default 18.18.0
nvm use default
# Install global packages
npm install -g @vercel/cli
npm install -g netlify-cli
npm install -g typescript
npm install -g ts-node
npm install -g @angular/cli
npm install -g create-react-app
npm install -g next
npm install -g prisma
npm install -g supabase
npm install -g firebase-tools
Productivity Applications
Raycast: The Spotlight Replacement
My most-used Raycast commands and configurations:
// Raycast shortcuts and workflows
{
"shortcuts": {
"calculator": "cmd+shift+c",
"clipboard_history": "cmd+shift+v",
"window_management": "cmd+shift+w",
"color_picker": "cmd+shift+p",
"emoji_search": "cmd+shift+e",
"file_search": "cmd+space",
"app_switcher": "cmd+tab"
},
"custom_commands": [
{
"name": "Open Project",
"command": "cd ~/Projects && find . -name package.json -maxdepth 2 | head -10",
"shortcut": "cmd+shift+o"
},
{
"name": "Kill Port",
"command": "lsof -ti:$1 | xargs kill",
"shortcut": "cmd+shift+k"
},
{
"name": "Generate UUID",
"command": "uuidgen | tr '[:upper:]' '[:lower:]'",
"shortcut": "cmd+shift+u"
}
]
}
Rectangle: Window Management
My Rectangle configuration for efficient window management:
{
"left_half": "cmd+option+left",
"right_half": "cmd+option+right",
"top_half": "cmd+option+up",
"bottom_half": "cmd+option+down",
"maximize": "cmd+option+return",
"center": "cmd+option+c",
"first_third": "cmd+option+d",
"center_third": "cmd+option+f",
"last_third": "cmd+option+g"
}
Database and API Tools
Database Tools Configuration
# Database connection configs
databases:
postgresql:
tool: "TablePlus"
connection_string: "postgresql://user:password@localhost:5432/dbname"
mysql:
tool: "Sequel Ace"
connection_string: "mysql://user:password@localhost:3306/dbname"
redis:
tool: "Redis Insight"
connection_string: "redis://localhost:6379"
mongodb:
tool: "Studio 3T"
connection_string: "mongodb://localhost:27017/dbname"
API Testing Setup
My Postman workspace organization:
// postman-environment-variables.js
{
"development": {
"baseUrl": "http://localhost:3000",
"apiKey": "dev-api-key"
},
"staging": {
"baseUrl": "https://staging-api.mikul.me",
"apiKey": "staging-api-key"
},
"production": {
"baseUrl": "https://api.mikul.me",
"apiKey": "prod-api-key"
}
}
Automation Scripts
Project Initialization Script
#!/bin/bash
# create-project.sh
PROJECT_NAME=$1
PROJECT_TYPE=$2
if [ -z "$PROJECT_NAME" ]; then
echo "Usage: create-project.sh <project-name> [next|react|node]"
exit 1
fi
cd ~/Projects
case $PROJECT_TYPE in
"next")
npx create-next-app@latest $PROJECT_NAME --typescript --tailwind --eslint --app --src-dir --import-alias "@/*"
;;
"react")
npx create-react-app $PROJECT_NAME --template typescript
;;
"node")
mkdir $PROJECT_NAME
cd $PROJECT_NAME
npm init -y
npm install express
npm install -D @types/node @types/express typescript ts-node nodemon
;;
*)
mkdir $PROJECT_NAME
cd $PROJECT_NAME
git init
touch README.md
;;
esac
cd $PROJECT_NAME
# Create standard files
echo "node_modules/
.DS_Store
.env.local
.env
dist/
build/" > .gitignore
# Initial commit
git add .
git commit -m "Initial commit"
# Open in VS Code
code .
echo "Project $PROJECT_NAME created successfully!"
Daily Development Routine
#!/bin/bash
# morning-routine.sh
echo "🌅 Starting morning development routine..."
# Update system
echo "Updating Homebrew..."
brew update && brew upgrade
# Update global npm packages
echo "Updating global npm packages..."
npm update -g
# Clean up Docker
echo "Cleaning Docker..."
docker system prune -f
# Update projects
echo "Updating project repositories..."
find ~/Projects -name ".git" -type d -execdir git pull \;
# Show git status for all projects
echo "Git status for all projects:"
find ~/Projects -name ".git" -type d -execdir pwd \; -execdir git status --short \;
echo "✅ Morning routine complete!"
Performance Monitoring Script
#!/bin/bash
# system-monitor.sh
echo "🖥️ System Performance Monitor"
echo "================================"
# CPU usage
echo "CPU Usage:"
top -l 1 | head -n 10 | grep "CPU usage"
# Memory usage
echo "Memory Usage:"
vm_stat | grep -E "(free|active|inactive|wired|compressed)"
# Disk usage
echo "Disk Usage:"
df -h | head -n 5
# Network activity
echo "Network Activity:"
nettop -l 1 | head -n 10
# Running processes
echo "Top Processes:"
ps aux | sort -nr -k 3 | head -n 10
# Docker containers
if command -v docker &> /dev/null; then
echo "Docker Containers:"
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
fi
The Results: Measurable Productivity Gains
After implementing this setup, here's what I measured over 6 months:
// productivity-metrics.js
const productivityGains = {
timesSaved: {
commandLineOperations: '45 minutes/day',
fileNavigation: '30 minutes/day',
windowManagement: '15 minutes/day',
gitOperations: '25 minutes/day',
totalDaily: '115 minutes/day'
},
efficiency: {
codeWritingSpeed: '+25%',
bugDebuggingSpeed: '+40%',
projectSetupTime: '-60%',
contextSwitching: '-50%'
},
qualityImprovements: {
codeQuality: 'Consistent formatting and linting',
gitCommitQuality: 'Better commit messages with templates',
documentation: 'Auto-generated and updated',
testCoverage: 'Increased by 30%'
}
};
Backup and Sync Strategy
Dotfiles Management
I maintain all configurations in a Git repository:
#!/bin/bash
# sync-dotfiles.sh
# Repository: https://github.com/mikulgohil/dotfiles
# Symlink all configuration files
ln -sf ~/dotfiles/.zshrc ~/.zshrc
ln -sf ~/dotfiles/.gitconfig ~/.gitconfig
ln -sf ~/dotfiles/.vscode/settings.json ~/Library/Application\ Support/Code/User/settings.json
ln -sf ~/dotfiles/.vscode/keybindings.json ~/Library/Application\ Support/Code/User/keybindings.json
ln -sf ~/dotfiles/starship.toml ~/.config/starship.toml
# VS Code extensions
if command -v code &> /dev/null; then
cat ~/dotfiles/.vscode/extensions.txt | xargs -n 1 code --install-extension
fi
echo "Dotfiles synced successfully!"
Automated Backups
#!/bin/bash
# backup-configs.sh
BACKUP_DIR="$HOME/Backups/$(date +%Y-%m-%d)"
mkdir -p $BACKUP_DIR
# Backup VS Code settings
cp -r "$HOME/Library/Application Support/Code/User" "$BACKUP_DIR/vscode"
# Backup terminal configs
cp ~/.zshrc "$BACKUP_DIR/"
cp ~/.gitconfig "$BACKUP_DIR/"
cp ~/.config/starship.toml "$BACKUP_DIR/"
# Backup Homebrew packages list
brew list --cask > "$BACKUP_DIR/brew-cask.txt"
brew list --formula > "$BACKUP_DIR/brew-formula.txt"
# Backup npm global packages
npm list -g --depth=0 > "$BACKUP_DIR/npm-global.txt"
echo "Backup completed: $BACKUP_DIR"
Key Takeaways
After 5 years of iteration, here's what I've learned:
- Automate everything - If you do it more than twice, script it
- Consistency is key - Same shortcuts, same tools, same workflows everywhere
- Less is more - 15 carefully chosen VS Code extensions beat 50 random ones
- Measure impact - Track time saved and productivity gains
- Version control configs - Treat dotfiles like code
- Regular maintenance - Update and prune monthly
The setup I've shared isn't just about tools—it's about creating an environment where you can think clearly and work efficiently. Every optimization, every shortcut, and every automation serves the goal of reducing friction between your ideas and their implementation.
Start with one section, perfect it, then move to the next. Your future self will thank you for the investment.