Your Dev Environment, Set Up Right
Your Dev Environment, Set Up Right
The 30-minute setup
If you take nothing else from this piece, do these three things right now and you'll be ahead of where I was a year in.
- Install a real terminal (not the default one your OS came with)
- Install Cursor as your editor
- Install the GitHub CLI (
gh)
That's the floor. Thirty minutes, three downloads. Everything else in this resource is optimization on top of those three.
The reason these three: AI coding tools live in the terminal and the editor. The terminal you ship with on Mac or Windows is fine for occasional use and bad for daily use. The editor you choose shapes how you work every minute you're awake. The GitHub CLI is the connective tissue that lets you move between your code and your repos without breaking flow. Get those right and the rest is upgrades.
The longer version, by category, follows.
Terminal
This is the application you'll spend the most time in. Pick one that doesn't fight you.
Mac: Ghostty. It's fast, the defaults are sane, the font rendering is sharp, and it doesn't suffer from the slow startup that older terminals have when you've got a busy shell config. I switched from iTerm2 to Ghostty in early 2026 and have not missed iTerm once. The only reason to stay on iTerm is if you have years of muscle memory in its specific shortcuts — that's a real cost, don't minimize it.
Windows: Windows Terminal. Microsoft's own terminal app, free in the Microsoft Store. It supports WSL2 natively, which is where you actually want to do your work — Windows-native dev tools are still a worse experience than the Linux toolchain running inside WSL. Set up Windows Terminal, install Ubuntu via WSL, and treat the Linux side as your real environment.
Linux: Alacritty. Fast, GPU-accelerated, configured via a single TOML file. There are other good choices (Kitty, WezTerm) but Alacritty has the smallest config surface, which I value when I'm bootstrapping a new machine.
The thing terminals are for is staying out of your way. The default Mac Terminal and PowerShell are not bad applications — they're just full of compromises for backward compatibility. Modern terminals shed those compromises. The improvement is real.
Shell
This is where the controversy lives. Pick one. Stop researching.
zsh + Oh My Zsh. The default on modern Mac, ships with a clean plugin ecosystem. Oh My Zsh gives you theme presets, autosuggestions (gray text completion of your previous commands), and syntax highlighting. Add the zsh-autosuggestions and zsh-syntax-highlighting plugins as soon as you install. They're the two that earn their keep daily.
fish. Different shell, different philosophy. Defaults are dramatically better than zsh — autosuggestions, syntax highlighting, and a clean config language all built in, no plugins needed. The cost is that fish is not POSIX-compatible, which means scripts written for bash/zsh sometimes don't work as-is. For your interactive shell, this is fine. For shell scripts, write them in bash regardless of what your interactive shell is.
The controversy: many developers swear by fish and never go back. Others find the POSIX incompatibility a dealbreaker. My take — if you're new, start with zsh + Oh My Zsh. It's the well-trodden path, and every tutorial assumes it. If you're experienced and curious, fish is genuinely better at being an interactive shell. Either choice is defensible. Both will frustrate you in the same week the AI tooling moves.
Whatever you pick, do this once and stop tinkering. Shell configuration is a black hole. I've watched people spend more time configuring their terminal than using it. Set it up, get to "good enough," go build something.
Dotfiles
Dotfiles are the configuration files that make your environment yours. Put them in a git repo. Sync them across machines. Survive disk failures.
Minimum starter:
~/dotfiles/
.zshrc or .config/fish/config.fish
.gitconfig
.gitignore_global
.config/ghostty/config
install.sh (symlinks files to home directory)The install.sh script is the part most people skip. It's the one that makes the dotfiles useful. The pattern is simple: for each file in the repo, create a symlink from ~/.zshrc (or wherever it belongs) to the file in the repo. Now editing the file in the repo updates your live config, and you can commit changes as you go.
What goes in each:
.zshrc / config.fish — your aliases (gs for git status, gp for git push, .. for cd ..), your prompt customization if any, your PATH additions, your environment variables that aren't secrets.
.gitconfig — your name, email, default branch (main), pull strategy (rebase = true), and a few aliases (co for checkout, br for branch). Set core.excludesfile to point at your global gitignore.
.gitignore_global — the OS-specific files that shouldn't be in any repo. .DS_Store on Mac. Thumbs.db on Windows. Editor swap files. Set this once and never think about it again.
Terminal config — fonts, color scheme, padding, key bindings. The little things you tweak that make your terminal feel right.
That's it. Five files. Maybe a hundred lines of config total. Anything more than that and you're optimizing instead of building.
Watch out
The trap with dotfiles is treating them as a project instead of as infrastructure. The job is "set up once, sync across machines, get out of the way." If you find yourself spending a Saturday refactoring your zsh config, you've crossed the line. Set a budget of one hour a quarter for dotfiles maintenance. More than that is a hobby, which is fine, but call it that.
Editor
Cursor as default. It's a fork of VS Code with AI built in. Every shortcut, every extension, every config file works the same as VS Code. The added AI features — Cmd-K for inline edits, Cmd-L for chat, tab completion across multi-line predictions — are integrated more deeply than you can get with VS Code plus a Copilot extension. For most people, most of the time, Cursor is the right default.
VS Code if you want vanilla. Same editor minus the AI integration. If you do most of your AI work in a separate terminal (Claude Code, Codex) and want your editor to be just an editor, this is the choice. Lots of professional developers prefer this — the cognitive load of an AI editor on top of an AI terminal can be too much.
Both editors support every language you'll touch. Both have good extension ecosystems. Both are free. The choice is about how integrated you want AI to be in the editing surface itself.
I switched to Cursor in 2025 and stayed. The tab completion alone saves me enough time to justify it. But I keep VS Code installed for when I want to work in a quieter environment, and I'd recommend the same.
What I don't recommend: vim/neovim as your daily driver if you're newer to development. They're great editors and there's a reason serious engineers use them. But the learning curve eats months of productivity you don't have to spare when you're still building your foundation. Come back to them in a few years if you're curious. Until then, Cursor or VS Code.
CLI tools you actually use
A handful of CLI tools that I use weekly and recommend installing immediately:
gh (GitHub CLI) — create repos, open PRs, view issues, all from the terminal. gh pr create, gh repo create, gh issue list. The thing this replaces is opening github.com twenty times a day.
ripgrep (rg) — search code recursively, faster than grep. Honors .gitignore by default, so it doesn't waste time grepping through node_modules. The first tool I install on any new machine.
fzf — fuzzy file finder. Pipe anything into it, type to filter, press enter to select. The killer use case is cd $(find . -type d | fzf) to jump to any directory by typing a partial name.
bat — like cat but with syntax highlighting and line numbers. Replace your cat alias with bat and reading files in the terminal becomes pleasant.
jq — JSON parsing in the shell. Essential the first time you have to extract a value from an API response in a script.
httpie — friendlier curl. Better defaults, prettier output, JSON support without fighting quote escaping. I use it for any API exploration before I commit code that calls the endpoint.
Install them via Homebrew on Mac, Scoop or winget on Windows, or your package manager on Linux. Total install time: under five minutes. Time saved: a lot, forever.
Env file management
The .env.local pattern is the convention every modern framework follows. Files named .env.local, .env.production, etc. are loaded automatically by Next.js, Vite, and most other tools. They're ignored by git by default (or should be — verify).
The rules I follow:
-
.env.localis gitignored. Always. No exceptions. Verify by runninggit statusafter creating it. If it shows up, something's wrong with your.gitignore. -
.env.local.exampleis committed. This is a template with the keys but no values. New contributors can copy it to.env.localand fill in their own keys. The.examplefile is also self-documenting — anyone looking at your repo can see what env vars they need. -
Production secrets live in Vercel/Fly/wherever you deploy. Never in a file. Never in a Slack message. Never in a screenshot. Set them in the platform's env var UI or via their CLI.
-
When in doubt, rotate. If you ever leak a secret — committed by accident, pasted into a chat, anything — assume it's compromised and rotate it. Two minutes of inconvenience is cheaper than a breach.
I learned this the hard way
The first time I leaked an API key, it was committed to a public repo for 11 minutes before I caught it. By the time I rotated, a scraper had picked it up and used it. The bill was $80. Most providers have free monitoring that catches this — turn it on. GitHub has secret scanning built in for many providers. Use it.
The "I'm on a new machine" recovery procedure
Eventually you'll set up a new machine. The dotfiles repo plus a written checklist makes this a one-hour process instead of a one-day one.
The checklist I keep in a setup.md at the root of my dotfiles repo:
Install Xcode CLI tools (Mac): xcode-select --install
Install Homebrew: /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
Install Brewfile contents: brew bundle --file=~/dotfiles/Brewfile
Clone dotfiles: git clone git@github.com:me/dotfiles.git ~/dotfiles
Run install: cd ~/dotfiles && ./install.sh
Install Cursor manually (or via brew cask)
Set up SSH key for GitHub: ssh-keygen -t ed25519 -C "email@example.com" then upload to GitHub
Sign into GitHub CLI: gh auth login
Install Node via fnm or nvm
Pull down the most recent project: cd ~/Projects && git clone [main project]
Copy .env.local from 1Password
npm install && npm run dev — verify it worksTwelve steps. About an hour. The point is that none of it is figured out under pressure — it's a checklist you wrote when calm. The first time you have to do this is the worst time to figure it out.
The Brewfile is the file you generate by running brew bundle dump. It's a list of every tool, library, and Mac app you have installed via Homebrew. Re-running brew bundle on a new machine reinstalls all of them. Commit your Brewfile to dotfiles. Update it every few months.
That's the whole setup. Not optimized. Not impressive. Just working. The point of a dev environment is to disappear under your hands while you build the thing. Set it up once, commit the config, and stop touching it for a while. Go build.