Moving My Dotfiles to Nix

I've been experimenting with Nix. I have a PC that is way more powerful than my older Macbook. While experimenting with Ubuntu on WSL, and porting my existing dotfiles over, I remembered my friend Tom talking about Nix and NixOS and decided to give it a whirl.

Two weeks later this article is being written on NixOS, in WSL, using my full dev environment. 🎉


The orange site and red site are filled with excellent articles about Nix and what it can do. For the sake of this article a brief overview.

The word Nix points to three things:

  1. A functional language1 for describing configurations of software.
  2. A package manager using the Nix Language to handle installation and path management of software configurations.
  3. A *nix OS (NixOS) that can be configured using the Nix Language.

These three things provide a couple features very desirable to me:

  • Using a strict configuration for my dev environment means that I can sync my setup between my work laptop, my personal laptop, and now this development WSL PC.
  • NixOS being a configuration-first OS means I can summon a direct copy of it without having to spend hours setting it up. This is advantageous for virtualisation or if I want to move my WSL setup to a dual-boot someday.

MacOS or WSL

Wezterm works on both my "host" OS. I just run the executable and put my wezterm.lua wherever it needs to be.

I do have a wild little script that runs and installs the wezterm terminfo file. Very un-nix.

On my Macs I can't run NixOS but I can at least install the Nix Package manager. There's a relatively complicated install process involving a separate volume and mounting… but the installer is pretty easy to run.

On the Windows PC I used the WSL2 instructions provided by NixOS. I also added

default_domain = 'WSL:NixOS'

to my Windows .wezterm.lua so that Wezterm will connect to WSL on launch.

Home Manager

After NixOS or Nix Package Manager have been installed we can install Home Manager manage our dev environment.

It's specifically built for this problem and replaces what I was doing with my Brewfile, Makefile, and stow.

I took it slowly over a couple of weeks. At first my home-manager consisted of installing some packages and moving my existing dotfiles to the right place. Very un-Nix-like but it totally worked.

As I explored the options appendix and debugged problems I wound up here today. I chose not to put everything into the Nix configuration and keep some of the configuration in files for backwards compatibility. In a pinch you could stow or ln those folders/files in your home just like I was before.

Let's explore some of the bumps in the road.


I eventually moved to using the programs.neovim configuration provided by Home Manager. I really wrestled with getting everything setup correctly. I think part of the problem was existing executables and configuration files still in path on OSX that was confusing the universe but in the end there were two big problems:

Treesitter wants to compile

Treesitter is awesome. But it wants to run scripts and compile things. Nix's store doesn't love that… it wants each folder to be idempotent and sets them to Read Only.

I added pkgs.vimPlugins.nvim-treesitter and eventually found the sequence of settings to make it work:

  • add config block to configure highlight and indent on, but I got errors… set type = "lua";.
  • use withAllGrammars so that it automatically gets all of them.
  • everything is installed but not loading, use packadd to force it to load the package.

All this wasn't working and I realized that…

Lazy.nvim takes over RTP

Turns out my beloved Lazy.nvim completely takes over the RTP. This means that plugins loaded manually (or by Nix!) can't be found by neovim. Someone else pointed out there was a setting, so I was able to disable this and suddenly neovim could see plugins loaded by Nix.

These may be bad and wrong, if so… shoot me an email?


Having learned from my Neovim mistakes Tmux was a bit easier. Like Treesitter, TPM wants to modify it's read-only folders. I moved some settings into the configuration, install the plugins using Home Manager, and use my existing config for theming and style.


I've been using a stripped down Fish install for a while now. I almost wonder if I should use it at all. I basically just install it and use Home Manager to enable Starship.

I still am using asdf in some places. It'll likely phase out as I get better at flakes.

I'm starting to play with and flakes to create my development environments. At the moment I'm still making heavy use of asdf to handle ruby/js package management. I am wrestling with how to manage gems that want to build native extensions. I've been warned by kind friends that it's enough to drive one crazy… but I've got the bandwidth presently for the challenge.

I like the idea of only enabling LSP executables and maybe even entire Neovim configurations per project using flakes and overlays. I've got a really simplistic version of this working using direnv at the moment.

All this very much falls under XKCD's warning of automation addiction. For me it's worthwhile to learn a little bit about Nix and to face the puzzle of *nix and pathing problems.

I really love that I can run home-manager switch and know that everything I need to start working gets automatically put in the right place. That's pretty hard to beat.

Now I suppose it's actually time to read Nix's actual documentation. :P

  1. Nix loves the trailing ;. Absolutely required. Really hard for my ruby/JS brain. 

  • 2023-11-28 17:41:49 -0600
    add link

  • 2023-11-28 17:47:59 +0000
    Post about nix