/home/leela projects blog experiments
> pandoc -t html5 /run/user/leela/blog/nix-getting-started.md

Introduction to Nix, using Home Manager

Dec 31 2023

After recently switching to Nix myself, I thought I’d write a post about why you should too, and how to get started! :3

Note that this article isn’t quite finished yet and will probably be expanded at some later date.

What is Nix?

Nix can be broken down into 3 parts that all interact with each other:

How does Nix differ from other package managers?

Other package managers are imperative, where you specify what you want installed by giving instructions. For example, apt install zsh to install the zsh shell using apt.

Nix is declarative. Instead of telling it what to do, you tell it what you want to end up with.
For example, putting programs.zsh.enable = true; inside your configuration.

Why do this?

The big advantage to Nix’s approach is that your configuration contains the entire system state. Want to reinstall? Just copy over your configuration, apply it, and you’re back to where you were.
This gets especially powerful with multiple systems, as configuring them in bulk is trivial with this approach.

It solves a similar use-case as something like Ansible, but is much less cumbersome in doing so.

Great, how do I start?

Nix is sadly also very complex - IMO the easiest way to get started is Home Manager, which is what this article will be about!

Home Manager will allow you to manage your dotfiles on any distro, using the Nix package manager and configuration written in the Nix language.

Installing Nix and Home Manager

The first step will be to install Nix and HM:

# Install Nix the package manager in multi-user mode.
sh <(curl -L https://nixos.org/nix/install) --daemon

# Install the HM 'channel', which is where Nix gets it's packages,
# and update the packages available in our channels
nix-channel --add https://github.com/nix-community/home-manager/archive/master.tar.gz home-manager
nix-channel --update

# Install home manager into our $HOME.
# This is done by creating a new shell with home-manager in it, then
# running 'home-manager -A install' inside that shell.
nix-shell '<home-manager>' -A install

We now have both Nix and HM available! To make sure your shell properly has them loaded, make sure to source $HOME/.nix-profile/etc/profile.d/hm-session-vars.sh inside of your .zshrc, .bashrc or similar.

Next steps

With HM installed, we now have our configuration inside .config/home-manager/home.nix.

It is strongly recommended at this point to make this directory a git repository or to keep track of versions and changes in some other way!

Otherwise, we’re ready to start writing some config - I recommend using VSCodium, as a plugin for the Nix language is available.

Writing our first configuration

For now, let’s write our first bit of configuration.
Let’s say we want to use lsd - open your home.nix and add the following:

programs.lsd.enable = true;

If you now run home-manager switch, you should be able to use lsd!

Going a little further

While this is nice, we would also like to configure lsd. HM makes this easy:

  programs.lsd = {
    enable = true;
    settings = {
      color.when = "always";
      icons.when = "always";
      date = "relative";

If we run home-manager switch, lsd will now run with our new configuration specified.

Rolling back

Let’s say we make a change to our configuration and decide we want to roll back to a previous one, as a change didn’t work as expected.

With Home Manager this becomes trivial:

# List all of our 'generations', where each is a time we used 'switch'
# to switch to our config
home-manager generations
# You will see a path for each generation. Copy the path of the generation
# you wish to activate, and run the activate script in it!
# (Random path here, for demonstration)

That’s it! You’re now back to your old configuration.


Once we start porting our configuration to Nix, we’ll quickly have it become quite large. Having everything inside of home.nix will be cumbersome, so let’s put it into a separate module.

In your home.nix, remove what we wrote for lsd and instead add:

imports = [ ./lsd.nix ];

Then in lsd.nix, write:

{ config, pkgs, lib, ... }: {
  programs.lsd = {
    enable = true;
    settings = {
      color.when = "always";
      icons.when = "always";
      date = "relative";
      sorting.dir-grouping = "first";

You can use imports in this manner to make your config modular.

Further reading

For now, this article ends here. Some articles to keep you going:

If you want an idea of what to do next, why not try porting your shell’s configuration?
Here’s my zsh module for some inspiration!

> cd ..