A New Machine Made Me Realize Dotfiles Aren't Optional

New work laptop, 2 hours hunting for old configs. Realized 5 years of workflow setup gone in 1 day. Config is code, and code must be tracked. Dotfiles repo philosophy: version control your config.

· · 9 min read

Last Tuesday I got a new work laptop. Slick, fast, fresh install. Happy. I opened the terminal, ready to code. Typed gst (my alias for git status) - command not found. Typed vim - default vim, not my neovim. Opened VS Code - default settings, my font gone, my theme gone, my snippets gone.

2 hours I spent hunting for old configs. The old laptop was already wiped. Backup? None. I realized: 5 years of building a workflow, gone in 1 day. Aliases, git config, editor settings, tmux config, SSH keys - all gone. I had to rebuild from scratch, trying to remember what I'd set up before.

That was the moment I understood why senior devs always version-control their dotfiles. Not for style. Because config is code, and code must be tracked. This isn't a tutorial on "X dotfiles you need." This is the story of why I finally made a dotfiles repo, and what I learned from the process.

---

What Are Dotfiles (Briefly)

Dotfiles = configuration files whose names start with a dot (hidden files in Unix). ~/.bashrc, ~/.gitconfig, ~/.config/nvim/init.lua, ~/.tmux.conf. Every dev has their own set. Every dev has different preferences. Every dev - if they've been coding long enough - has config that's been tweaked over years.

The problem: those configs are hidden, scattered, and don't automatically sync between machines. New laptop = start from zero.

The dotfiles repo philosophy: config is code, and code should be version-controlled. You wouldn't write an app without git. Why not your config?

---

The "Ah, I Should Have Known" Moments That Kept Repeating

Not just new laptops. The moments that finally made me realize:

Production server down at 3am. I SSH'd into the server. Default tmux, no config. I wanted to split the window - couldn't remember the default shortcut (prefix Ctrl+b, different from my Ctrl+a prefix). Debugging was slow because I struggled with unfamiliar keybindings. First 30 minutes were just fighting tmux.

Pair programming on a friend's laptop. Friend uses VS Code, I use neovim. I didn't know their keybindings. Every time I wanted to navigate, I had to ask "how do I find file X?" 1 hour of pair programming, 40 minutes of workflow struggle.

New VM for testing. I'd spin up a VPS, install tools, configure shell. 45 minutes of setup. Even though I'd done it 10 times this year. Every time, I'd re-remember the same configs. Every time, a step was missed. Every time, frustration.

When I finally decided to make a dotfiles repo, 3 days to set everything up. But after that, a new machine = 1 command ./install.sh, 5 minutes running. 3 days invested, returns forever.

---

What I Keep in My Dotfiles Repo

Not a checklist. What I keep, and why:

Shell config (~/.zshrc or ~/.bashrc). Aliases, paths, prompt customization. Examples I use every day:

Navigation
alias ..='cd ..'
alias ...='cd ../..'
alias dev='cd ~/dev'

Git - these save the most time
alias gs='git status -sb'
alias gd='git diff'
alias gco='git checkout'
alias glog='git log --oneline --graph --decorate -20'

Quick project switch - using fzf
function pj() {
cd ~/dev/$(ls ~/dev | fzf)
}

Prompt - minimal, shows git branch
parse_git_branch() {
git branch 2> /dev/null | sed -nE 's/^\* (.*)/\1/p'
}
PS1='\w \[\033[32m\]$(parse_git_branch)\[\033[0m\] → '

Every alias exists because I typed the same command 100x a day. git status -sb → gs. 12 characters to 2. 6x faster. Set once, forever.

Git config (~/.gitconfig). User, editor, aliases, pretty format:

[user]
name = Sendi Noviansyah
email = muhammad.sendi@msncode.dev

[core]
editor = nvim
autocrlf = false

[alias]
co = checkout
br = branch
ci = commit
st = status -sb
unstage = reset HEAD --
last = log -1 HEAD
visual = !gitk
amend = commit --amend --no-edit

[init]
defaultBranch = main

[pull]
rebase = true

pull.rebase = true - linear history, no merge commit noise. A decision I made 3 years ago, still holding.

Editor config (~/.config/nvim/). Init.lua, plugin list, LSP config, keybindings. The most complex but most valuable. I use lazy.nvim for plugin management, mason for LSP servers. Setting up neovim from scratch takes 2 days, but now every machine I use has an identical editor.

tmux config (~/.tmux.conf). Prefix key, split bindings, mouse support, theme:

Change prefix from Ctrl+b to Ctrl+a (easier to reach)
set -g prefix C-a
unbind C-b
bind C-a send-prefix

More intuitive splits
bind | split-window -h -c "#{pane_current_path}"
bind - split-window -v -c "#{pane_current_path}"

Mouse support
set -g mouse on

Reload config with r
bind r source-file ~/.tmux.conf \; display "Reloaded!"

Start window index at 1
set -g base-index 1
setw -g pane-base-index 1

SSH config (~/.ssh/config). Host aliases so you don't type long IPs:

Host prod
HostName 10.0.1.42
User deploy
IdentityFile ~/.ssh/prod_key
Port 2222

Host staging
HostName 10.0.2.42
User deploy
IdentityFile ~/.ssh/staging_key

Now ssh prod instead of ssh -i ~/.ssh/prod_key -p 2222 deploy@10.0.1.42. 47 characters to 8.

---

Setting Up the Dotfiles Repo: How I Manage It

There are several approaches. What I use: git bare repo. Simple, no extra tools needed.

Create a bare repo
git init --bare $HOME/.cfg

Alias to manage dotfiles
alias config='/usr/bin/git --git-dir=$HOME/.cfg/ --work-tree=$HOME'

Hide files you don't want to track
echo ".cfg" >> .gitignore

Add files
config status
config add .zshrc .gitconfig .tmux.conf
config commit -m "init dotfiles"
config push

To add new config:

config add .config/nvim/init.lua
config commit -m "feat: add neovim config"
config push

New machine, restore:

echo ".cfg" >> .gitignore
git clone --bare git@github.com:0xNN/dotfiles.git $HOME/.cfg
alias config='/usr/bin/git --git-dir=$HOME/.cfg/ --work-tree=$HOME'
config checkout
config config --local status.showUntrackedFiles no

5 lines. All configs back.

Popular alternatives:
• GNU Stow - symlink farm, great if your configs are scattered across many folders
• chezmoi - dedicated dotfiles management tool, supports templates + secrets
• yadm - yet another dotfiles manager, a git wrapper with extra features

I use the bare repo because it's simple. But if your configs are already complex (multiple machines, secrets, conditional configs), chezmoi is worth trying.

---

What I Learned From Making Dotfiles

Config is code. Treat it like code: version control, clear commit messages, documentation. If you add an alias, the commit message is "feat: add gst alias for git status -sb". Not "update". If 6 months later you forget why that alias exists, git blame answers.

Backup isn't enough. Backing up a file = you have a snapshot. Version control = you have history, branching, easy restore. Different. A dotfiles repo isn't just a backup, it's a documentation of decisions. Why is the tmux prefix Ctrl+a not Ctrl+b? Because a commit message from 2 years ago says "Ctrl+a is closer to home row, reduces finger stretch."

Dotfiles must be portable. If you hardcode machine-specific paths (/Users/sendi/...), it's not portable. Use $HOME or ~. If you have specific paths (project folder, binary paths), make them variables at the top, so they're easy to override per machine:

In .zshrc
export DEV_DIR="${DEV_DIR:-$HOME/dev}"
alias dev="cd $DEV_DIR"

New machine, just export DEV_DIR=/custom/path before sourcing .zshrc.

Don't over-engineer. I've seen dotfiles repos with 500 files, 50 scripts, 3 layers of abstraction. You're not building an OS. You're building config. If your install script takes 30 minutes to run, you've over-engineered. Target: ./install.sh runs in 2 minutes, all configs symlinked.

---

Common Misconceptions

"Dotfiles are only for senior devs." - No. A junior dev who just has the gs='git status' alias already has dotfiles. Start small, grow slowly. Doesn't have to be perfect from the start.

"Dotfiles repos must use a framework (oh-my-zsh, etc)." - Wrong. Frameworks make you fast initially, but are opaque. When something breaks, you don't understand why. Bare config + manual customization = you understand every line. Oh-my-zsh is fine for beginners, but graduate from it.

"Dotfiles are showing off." - There's a culture of dotfiles as flexing ("look at my neovim config, 1000 lines of lua"). That's not the point of dotfiles. The point: productivity + portability. If your config is 10 lines and sufficient, that's success.

"You must use tool X (stow, chezmoi, yadm)." - No. A bare git repo is enough for 90% of cases. Tools are only needed when your dotfiles are already complex. Don't adopt a tool before there's a problem to solve.

---

An Honest Closing

3 days to set up my first dotfiles repo. Now, new laptop = 5 minute setup. Server down at 3am = my tmux config is familiar, no fighting keybindings. Pair programming = just clone the repo, same workflow. Testing VM = 1 command, all tools ready.

The philosophy I learned: config is code, and code is an investment. Every alias, every keybinding, every customization - it's a decision you made, and that decision has value. If you don't version control, you throw away that investment every time you change machines.

If you don't have a dotfiles repo yet, start now. Doesn't have to be perfect. Start with 1 file: .gitconfig. Commit, push. Tomorrow add .zshrc. Next week add editor config. Slowly. But start now, before your next machine makes you realize the hard way.

I still add to my config every week. Every time I find repetition, I make an alias. Every time I find friction, I tweak a keybinding. My dotfiles repo isn't final, it's a living document. Just like my skills - not final, still growing.