TL;DR I spent years polishing a vim and tmux setup, then sat useless in front of a stock vim on a production server. So I learned the defaults I’d been overriding all along, and moved my customizations on top of them instead of in place of them. What that looks like for vim, tmux and the shell tools, and the four checks I use to find the gaps.
For years my setup was the thing I was proudest of. A dotfiles repo with commits going back further than some of my jobs, a vim config that pulled in thirty plugins, the tmux prefix moved somewhere comfortable, a prompt that took a weekend to get right. Down to the last keybinding, it was mine. On my laptop I was fast, and I hardly thought about the tools at all. Muscle memory did the work.
Then one evening I SSH’d into a production server to debug something, and I was useless.
No mappings, no plugins, no aliases. Just vim as it ships, with the default keys I’d quietly forgotten during the years I spent overriding them. I sat there fumbling through basic navigation like it was my first week, while a real problem waited. Everything I’d polished was on a machine three hundred kilometres away, and none of it could help me.
The setup only worked where the setup was installed. It took a production server for me to notice.
What I’d traded away
There’s a version of me that learned vim the way it ships before ever touching a plugin. Same skills, same brain. He logs into that same server, opens the same file, and nothing feels foreign, because the keys are the ones that were there from the start.
That version can sit down at any machine with vim on it and work. A colleague’s laptop while pairing. A locked-down client device. A fresh VM that needs debugging right now. The tooling doesn’t have to come along, because the competence lives in his hands. There’s no repo to clone first.
That’s the portability over personalization idea, pointed at my own workflow. Owning your infrastructure means being able to operate it from whatever chair you happen to be in. The same holds for skills. A skill that only works on one machine is a dependency, and I don’t get to reproduce that machine on a client’s server.
Where the cost hides
The rabbit hole is easy to fall into. You read about someone’s vim config on Reddit. You find a dotfiles repo with 3000 stars on GitHub. One more plugin and you’ll be so much faster. And you will be. On your machine. With your config.
The cost doesn’t show up on that machine. Every default you remap before learning it is a piece of portable knowledge swapped for a local convenience, and the swap is invisible right up to the moment you’re on someone else’s box with a deadline.
Two people can look identical while everything works. One knows the defaults and chose to override them. The other never learned them and only knows the custom setup. Drop both onto a stock system and the difference is immediate. I was the second one.
The defaults were better than I remembered
So I went back and learned them. Slower than I’d have liked, on my own laptop, where nothing forced me to. And they have one property no plugin can match. They’re everywhere, and they’ve been everywhere for decades.
Vim: learn before you remap
Vim’s default keys are weird. No argument from me. They’re also consistent, and the core of them goes back to vi in the 1970s, so every vim on every Unix box answers to the same ones. That consistency was what I’d been throwing away.
Before you remap jk to escape, learn Ctrl+[. It works in vim, in bash, in anything built on readline. Before you install a fuzzy finder, learn :find and :edit **/*. Before you add custom text objects, get the built-in ones into your fingers. You can still remap everything later. You’ll just know what you’re giving up.
| Default | What it does | Why it matters |
|---|---|---|
Ctrl+[ | Escape | Works in every terminal, not just vim |
Ctrl+o / Ctrl+i | Jump list navigation | No plugin needed |
:!command | Run shell command | Available on any vim |
* / # | Search word under cursor | Instant, no config |
% | Jump to matching bracket | Built-in since forever |
gf | Go to file under cursor | Works out of the box |
Ctrl+a / Ctrl+x | Increment/decrement numbers | Underrated default |
I still run plugins and I still have a few mappings of my own. But I can sit down at any vim and be useful right away, because I know what it hands me for free.
Tmux: the prefix matters less than you think
The first thing everyone changes in tmux is the prefix, Ctrl+b to Ctrl+a. I did it too. Ctrl+b is awkward, and screen used Ctrl+a, so it felt like the obvious fix.
But look at what a prefix is. You press it once, then another key. The awkwardness of Ctrl+b is one keystroke, and after a few thousand of them your fingers stop noticing. Ctrl+a, meanwhile, collides with “go to beginning of line” in bash, which I reach for constantly. And every server with tmux on it uses Ctrl+b. Train on Ctrl+a and you fight the wrong prefix every time you leave home.
| Default | What it does |
|---|---|
Ctrl+b % | Vertical split |
Ctrl+b " | Horizontal split |
Ctrl+b o | Cycle through panes |
Ctrl+b z | Zoom pane |
Ctrl+b [ | Copy mode |
Ctrl+b d | Detach |
Ctrl+b ? | Show all keybindings |
That last one, Ctrl+b ?, is the lifeline on any tmux. You don’t have to memorize the bindings when the whole list is one keystroke away.
Shell tools: knowledge that travels
Same logic for grep, awk, sed, find and the rest of the Unix toolkit. I watch people install ripgrep and forget grep exists. They pick up fd and can’t remember find syntax any more. Everything gets aliased to the modern replacement until the original is a stranger.
The modern tools are good and I use them every day. But grep is on every Unix system. So is find. Awk and sed come preinstalled on every server you’ll ever touch. In the middle of an incident you don’t get to install ripgrep first. You work with what’s there.
# grep basics that work everywhere
grep -r "pattern" . # recursive search
grep -l "pattern" *.log # files containing pattern
grep -v "exclude" # inverse match
grep -E "regex|pattern" # extended regex
# find basics
find . -name "*.py" # find by name
find . -mtime -1 # modified in last day
find . -type f -exec cmd {} \; # execute on results
# awk one-liners
awk '{print $2}' file # print second column
awk -F: '{print $1}' /etc/passwd # custom delimiter
awk 'NR==5' file # print line 5
Ripgrep is faster and fd reads nicer. Grep and find are there. On a server you don’t control, the one that’s installed is the one you get.
Why I put it off for so long
So why did it take a production server to get me to do this? Because relearning the defaults felt like going slower on purpose. I had a config that worked. Sitting down to learn vim the boring way, on my own machine, for a payoff that only shows up on someone else’s, was a hard sell to a brain that wants results now.
There was sunk cost in it too. Real hours went into those dotfiles, and admitting that some of them had bought me a fragile local optimum stung a little. The repo has commits going back years and I’m fond of every one of them.
And most days I’m on my own machine. The whole point of a comfortable setup is living in it. The bill for portability only comes due now and then, which made it easy to keep not paying it.
Additions on top, nothing replaced
The setup stayed. What changed is the rule for what goes into it.
Additions are fine, replacements aren’t. My customizations sit on top of the defaults instead of erasing them. I don’t remap Ctrl+b. I add bindings, and the originals still fire. Colour schemes, a tidy prompt and a few mappings that don’t clash with anything built in all stay. The one question before overriding a default is whether it leaves me stranded on a fresh system. If yes, it doesn’t go in. I wrote up how I manage the repo with chezmoi and mise, and even there the config adds and never replaces.
The gaps hide until you go looking, so I test for them. Four checks:
- SSH into a server and edit a config file in vim, no plugins and no vimrc. Can you navigate, search, replace and save?
- Start a stock tmux session. Splits, moving between panes, new windows, all on the default bindings.
- Debug something with only grep and find. No ripgrep, no fd, no aliases. Can you find what you need?
- Write an awk one-liner that pulls a column out of a log file, without googling it.
Wherever you struggle, that’s a default worth learning, and it’s a lot cheaper to find out now than during an incident.
Three exceptions, and they’re real ones. If you have RSI or another physical limitation, remap whatever you need. Your health outranks portability. If your whole team standardizes on one config, that config is your default now. And if you never leave your own machine, never pair and never SSH anywhere, customize away. I don’t have that luxury.
The dotfiles repo is still there and still growing. What changed is that I could lose it tomorrow and still do my job. The next time I land in a minimal container with nothing but stock vim and a deadline, I’ll be a bit slower than at home, and that’s all.
