Simple Dotfiles

For as long as I can remember, tweaking my dotfiles repo has been my favourite way to procrastinate. When I was in school, when I was freelancing, and now at my corporate job, it's a constant in my programming practice.

So, it makes sense that, while trying to coming up with better things to write about, I write about dotfiles.

The Structure

At a high level, my dotfiles repo has one folder for each application that I want to configure:

❯ tree -L 1
├── alacritty
├── brew
├── git
├── mutt
├── nvim
├── scripts
├── tmux
├── vim
└── zsh

The one extra directory there is scripts, home to the install scripts.

Within each of these application directories live two1 types of files:

  • the actual config files (duh)
  • a links.prop file

The Configuration

The config files aren't much different from any other dotfiles repo you'll see out there (and honestly, there are better ones to look at). What I'm most pleased with in my current iteration, though, is the file naming pattern. In the past, I'd use file names like vimrc and zshrc ... which is pretty common, right? My gripe though: most editors don't give you syntax highlighting by default, when your file has no extension. So now I'm using file names like rc.vim and rc.zsh, and get the syntax highlighting. Small change, big difference.

As you can see, there's not too many apps I'm configuring. The three I've invested the most time in are definitely

I haven't used mutt in a few years, so it's likely a bit stale. The tmux config is good, but I've started using separate terminal windows more recently.

I think we'd all agree: one of the main idea of a dotfiles repo is symlinking all your files into place, so they remain under version control while they do their job from (usually) your home directory.

To that end, we have the links.prop files, one per app dir. Looks something like this:


On the left, we have the source. On the right, we have the destination. This is just a simple way to codify the symlinks that need to be created to "install" these configs. The script2 file will replace any environment variables in these lines, and then create the symlinks.

The Local Stuff

The script also creates a file called ~/ By default, it includes a single line:

export DOTFILES=/path/to/dotfiles

This file is for any machine-specific configuration. Need to include API keys or other secrets as env vars, but don't want to commit them? Have extra paths or tools that you need to configure for a work machine? Yes and yes, as a matter of fact.

Then, we source ~/ in the "root" ~/.zshrc. Actually, there's another trick here that I use for loading several config files that may not always exist. It's a little shell function called source_if_exists:

source_if_exists () {
if test -r "$1"; then
source "$1"

If the file exists, and is readable, then we'll source it! Another tiny tool, but it gives me a clear set of lines, like this:

source_if_exists $DOTFILES/zsh/aliases.zsh
source_if_exists $DOTFILES/zsh/history.zsh
source_if_exists $DOTFILES/zsh/p10k.zsh
source_if_exists $HOME/
source_if_exists $HOME/bin/
source_if_exists $HOME/.fzf.zsh

Ugh, so clean.

The Next Steps

The nature of dotfiles is to always be evolving. Next tax season, here's my shortlist for next features:

  • Add a solid install script for all tools and dependencies that I regularly use. I have a weak version of this right now, but it's incomplete. There's a thing called Homebrew Bundle that looks like a really solid start.

  • Configure MacOS itself. You can set a lot of macOS preferences from the command line. This feels like a no-brainer for me.

  • Support Linux. The base config I have here definitely works on the linux distros I've tried (so, Ubuntu ... and Raspbian, I guess). But once I have my whole env installation set up for macOS, it'd really lower the barrier-to-entry to have that for, say, Archlinux.

  1. Some apps also have an file ... idea in progress. ↩︎

  2. You can find a similar script in other people's dotfiles, but support for the links.prop is my own addition. ↩︎