Every great developer has a secret weapon hiding in their home directory.
It’s not a framework, a SaaS tool, or a $500 keyboard. It’s a folder calleddotfiles — and it’s the difference between a generic terminal that slows you
down and a tailored environment that disappears and lets you think.
This is my setup. Here’s what’s in it, how it’s built, and why every decision
was intentional.
Dotfiles are the hidden configuration files that live in your home directory —.zshrc, .tmux.conf, the entire ~/.config/nvim folder. They define how
every tool you use behaves: your editor, your shell, your terminal, your git
workflow.
Most developers cobble theirs together over years, copy-pasting from Stack
Overflow, never fully understanding what half of it does. The result is a
machine you can’t reproduce, can’t share, and can’t trust.
A well-structured dotfiles repo solves that. You clone it, run one command, and
your full environment is live in under ten minutes — on any machine.
## The Stack at a Glance
| Tool | Purpose |
|---|---|
| Neovim 0.11+ | Main editor — LSP, autocomplete, GitHub Copilot, debugging |
| Tmux | Terminal multiplexer — persistent sessions, split panes |
| Zsh + oh-my-zsh | Shell — autosuggestions, syntax highlighting, vi keybindings |
| Alacritty | GPU-accelerated terminal emulator |
| mise | Universal runtime version manager (replaces nvm, pyenv, sdkman) |
| GNU Stow | Symlink manager — deploys everything with stow . |
| Monaspace Nerd Font | Coding font with ligatures and dev icons, bundled in the repo |
| Catppuccin Mocha | Consistent color theme across every single tool |
Currently macOS-first — Linux support is coming, most of it already works.
## The Philosophy: One Source of Truth
The biggest mistake in most dotfiles setups is duplication. You configure your
LSP server in one file, its formatter in another, its linter somewhere else —
and when you want to add Go support, you touch six different files and miss
something.
This setup has a single file that owns every language decision:lua/config/languages.lua.
typescript = {
lsp = "vtsls",
formatters = {
"prettier"
},
linters = {
"eslint_d"
},
filetypes = {
"javascript",
"javascriptreact",
"typescript",
"typescriptreact"
},
lsp_config = {
settings = {
typescript = {
inlayHints = {
includeInlayParameterNameHints = "all",
includeInlayVariableTypeHints = true,
},
},
},
},
},
Add one entry here and you get: Mason auto-installs the language server and
formatter, conform.nvim knows how to format on save, nvim-lint runs the right
linter, and nvim-lspconfig gets the correct settings. Zero other files to touch.
That’s the design goal throughout — each tool reads from the same source,
nothing is repeated.
Neovim: A Real IDE, Not a Text Editor
This is the centerpiece. Neovim 0.11 introduced a native LSP API
(vim.lsp.config / vim.lsp.enable) that replaces a lot of boilerplate.
Combined with lazy.nvim for plugin management, the result is a startup that
feels instant.
What’s running under the hood
Completion (nvim-cmp) pulls from four sources in priority order:
GitHub Copilot → LSP → LuaSnip snippets → path completions. The popup is
narrow and intentional — no wall of noise.
Formatting (conform.nvim) runs on save, per language, with fallback to
the LSP formatter if a standalone tool isn’t available. The formatter list
is — you guessed it — pulled from languages.lua.
Linting (nvim-lint) runs on write, on buffer read, and on insert-leave.
Diagnostics use a clean inline dot prefix (●) rather than verbose inline text.
Debugging (nvim-dap) supports Python, Go, C/C++, JavaScript/TypeScript,
Bash, and Java — all pre-configured with the right adapters and keymaps out
of the box.
Git lives in two plugins that complement each other: vim-fugitive for
staging, committing, pushing, and blaming in a full-screen git buffer;
gitsigns for per-hunk staging, resetting, and inline blame in the statusline.
File navigation uses both neo-tree (sidebar tree view) and oil.nvim
(edit files like a buffer — rename, move, delete by just editing the text).
Telescope handles fuzzy-finding files, grep across the entire project, and
browsing help tags.
The Space leader
Every keymap uses Space as the leader. Groups are organized by intent:
- c — code (LSP: go to definition, rename, code action)
- f — find (Telescope)
- g — git (fugitive + gitsigns)
- d — debug (DAP)
- b — buffer (navigation, close, jump by number)
- ai — AI (CopilotChat: explain, fix, generate tests) which-key shows you what’s available after pressing the leader — so there’s
nothing to memorize. You discover it as you go.
Tmux: Your Sessions Are Sacred
Most people lose everything when they close a terminal. With tmux-resurrect,
your sessions — every window, every pane, every working directory — survive a
reboot.
The config keeps it minimal:
- Catppuccin Mocha statusline showing the app name, current session, working
directory, and CPU usage. - Vim-style pane navigation with hjkl — no reaching for arrow keys.
- Split panes that inherit the current path — open a new split in the same
project, not in ~. - Mouse support — for those moments when you just want to scroll. One thing worth calling out: catppuccin v2.x requires its config options to be
set before the plugin is sourced. A subtle ordering issue that breaks a lot of
setups. This one gets it right.
Zsh: A Shell That Stays Out of Your Way
The shell config is intentionally lean. Three oh-my-zsh plugins:
- git — a library of git aliases and prompt info
- sudo — double-press Esc to prepend sudo to the last command
- vi-mode — navigate and edit commands with vim motions Two shell enhancers loaded from Homebrew (with existence guards so a missing
package never breaks a new shell session): - zsh-autosuggestions — grayed-out completions from your history as you type,
accepted with the right arrow - zsh-syntax-highlighting — commands turn green when valid, red when not $EDITOR and $VISUAL are both set to nvim, so git commits, crontabs, and
anything else that opens a text editor get Neovim — not whatever vi resolves
to on a fresh machine.
mise: One Version Manager to Rule Them All
nvm, pyenv, rbenv, sdkman, goenv — each one a different install
process, a different shell hook, a different mental model. mise replaces all
of them with a single tool and a unified config format.
mise install node@lts python@latest java@21 go@latest
mise use –global node@lts python@latest java@21 go@latest
It activates via a shell hook in .zshrc and is transparent once set up.
No more “which node am I on?” moments.
Alacritty: The Terminal That Gets Out of Your Way
Alacritty is a GPU-rendered terminal that does very little intentionally.
No tabs, no built-in multiplexing — tmux handles that. What Alacritty gives
you is speed, a clean Catppuccin Mocha color palette, a blinking block cursor,
and Monaspace rendering with comfortable padding.
Font configuration uses two Monaspace variants: MonaspiceNe for regular and
bold, MonaspiceRn for italic — a deliberate mix that uses Monaspace’s
different stroke styles to visually separate code types.
GNU Stow: The Glue That Holds It Together
All of this would be useless if deploying it was a chore. GNU Stow solves that
elegantly.
Stow treats the dotfiles repo as a “package” and mirrors its structure into
your home directory as symlinks. Running stow . from inside ~/dotfiles
creates:
~/.zshrc → ~/dotfiles/.zshrc
~/.tmux.conf → ~/dotfiles/.tmux.conf
~/.config/nvim/ → ~/dotfiles/.config/nvim/
~/.config/alacritty/ → ~/dotfiles/.config/alacritty/
Every edit you make to your config is already in the repo — no copying, no
syncing. git commit and you’re done.
A .stow-global-ignore file excludes things that shouldn’t be symlinked:
the .git folder, the README, shell scripts, and per-machine configs like
the Copilot auth cache.
The Color System: Catppuccin Mocha Everywhere
Context switching between a dark terminal and a light editor — or worse, three
different accent colors — introduces subtle cognitive friction. You don’t notice
it, but it’s there.
Catppuccin Mocha is a warm, low-contrast dark theme with well-differentiated
accent colors. It has official integrations for every tool in this stack:
Neovim, tmux, Alacritty, lazygit, even the browser. When your editor, your
shell, your file tree, your git diff viewer, and your terminal chrome all share
the same palette, your environment fades into the background and lets the code
take center stage.
Who This Is For
This setup is built for developers who:
- Write across multiple languages and don’t want to re-configure for each one
- Want IDE features without an Electron app eating their RAM
- Care about reproducibility — set up a new machine in minutes, not days
- Prefer keyboard-driven workflows where the mouse is optional
- Want AI assistance built in, not bolted on as an afterthought It’s opinionated. It uses Neovim, not VS Code. Tmux, not a terminal’s built-in
tabs. Zsh, not fish. If that’s not your stack, most of the ideas — especially
the centralized language config and the Stow deployment model — translate to
any editor or shell.
Get It
git clone https://github.com/abdielreyes/dotfiles.git ~/dotfiles
cd ~/dotfiles
stow .
Full setup instructions, keymaps, and customization guide are in the README.
The config is macOS-first right now. Linux support is on the roadmap — the
Neovim and tmux configs are already fully cross-platform. Only the Homebrew
paths in .zshrc and the font install step need adjustment.
If you found this useful or have questions about any part of the setup, reach
out. Configuration is a craft — always improving.