Home sweet home

Posted on 12 February, 2020

The operations practice of defining infrastructure as code has been popular for a while, and it’s for good reason. Lot's of strange and unexpected things can happen to our very important web-servers, so being able to quickly build another one in a (close to) identical state can be very handy. Sadly, strange and unexpected things don't just happen to web-servers, they can happen our development machines too. And, heck, they're also pretty important.

Like infrastructure, can we define some of the state of our laptops using code? I'm not sure, but I think so, at least I'll explain what I've tried.

Bootstrapping scripts

First, I used a lightly modified fork of Ryan Bates' dot files which bootstraps itself using a lovely rake task.

This went pretty well. I didn't have to bootstrap new machines too often, I didn't really have many preferences regarding command line tools, and I only had so many technology stacks to be setup for.

The trouble came when I wanted to change things. It wasn't always clear to me that the changes I made would be applied properly when I ran the script on a fresh machine. It always seemed that I missed something and had to do some manual work in addition to the rake task.

The only part that I found to be very predicable were the files that were symlinked into my home directory. So after a while I cut the repository down to nothing but those.

Staying fresh

A colleague introduced a few us at Everydayhero to Fresh. It's great and with it I just started to feel that my development machine had become easily recoverable. I could run fresh on a minimally setup Macbook as well as on one I'd been working away on for months and the results were, more or less, the same.

Even though I still didn't do all that much with Fresh that couldn't be achieved with symlinking I did begin to see the potential.

Despite this I was still looking for something more complete. Fresh managed a lot, but it didn't manage everything. The plurality of thing managers I was using became apparent when I finally documented how I'd been setting everything up.

Home manager

I'd been using Nix as a Homebrew replacement for a while before finding Home manager. It's given me the ability to consolidate almost everything I need to setup and update my development machines into one command.

Apart from simplifying the process of setting up a new machine, Home manager has also allowed to me to manage more stuff more predictably.


There are a few non-default command line utilities I find myself always installing. Before Home manager if I wanted to setup a new machine I'd usually be moving lists of currently installed dependencies around.

brad@old $ brew list > deps.txt

brad@new $ xargs brew install < deps.txt

I'd moved to Nix before becoming aware of Homebrew Bundle's Brewfile, which looks like a great solution. Just not quite as holistic as I've found Nix / Home manager to be and with it my list of utilities is easy to manage.


Before Home manager I'd used a few of the popular Vim plugin managers (Pathogen, Vundle and Plug). They all worked well for me, but with my current setup I get a good plugin manager for Vim without an extra tool or installation step.


I've only ever used two Tmux plugins. Initially I installed them with TPM but now I install them with Home manager (Tmux sensible gets included by default).


Sometimes it's nice to string utilities together into useful aliases, or try to bring a little more consistency to working across both macOS and Linux. Sadly, those niceties can get out of hand, so I've found it useful to factor them out into bite-sized chunks.


I get a lot of use from Git bash completions and a few handy aliases.

I get all of that, and a few other things, installed and configured with one tool. What's more:

  • It's repeatable, if my environment bootstraps once I'm confident it'll do so again.
  • It's idempotent, I can keep running home-manager switch as often as I like without issues.
  • It works, more or less, the same on both my work machines running macOS and my home laptop running PureOS, a Debian fork. Because it's so repeatable I'm able to set up a build pipeline which ensures that every update I make will install happily on both platforms. I accept that this is perhaps taking things too far.

Now that I've said that, and now that I'm pretty comfortable with the approach, I expect I'll push it a little further. Why not?