Skip to content

Chapter 2 - Housekeeping

So far we’ve been working in one file with no VCS setup and no consistent formatting.

In this chapter we will…

  1. Get a Git repo set up for our system
  2. Learn how to compartmentalize our config into different files
  3. Do some setup for later chapters in flake.nix
  4. Setup auto-formatting for our code

Setting Up Git

Before we do anything, we’ll need to make a .gitignore.

  1. Create a .gitignore file to prevent unwanted files from being checked-in to VCS.
    • flake.nix
    • .gitignore
  2. I’d recommend this as a .gitignore.
    .gitignore
    # Symlink to anything nix built (no trailing slash)
    result
    # The VM image file QEMU creates for our VM
    nixos.qcow2
  3. Now initialize a new Git repo for your project.
    Terminal window
    git init
    git add .
    git commit -m "Initial Commit"

We now have a git repo for our config!

Fragmenting Our Config

Now we’ll split up our NixOS config from one file, this is for organization.

  1. Create files for each part of our config. To keep things clean, you probably want to put these in a folder called modules. flake.nix should not go in this folder, flake files must be in the root of the repo.

    Anything highlighted is something this guide is going to use later, so they’ll be required. Anything not highlighted is a suggestion based on how others tend to organize files, but pick what works best for you!

    • flake.nix
    • flake.lock
    • Directorymodules/
      • config.nix Sets up basics and imports all other modules
      • nix.nix Configures Nix itself within the VM
      • graphics.nix (DEs, apps, theming, etc)
      • shell.nix (Aliases, themes, etc)
      • Go wild!
  2. You’ll also need to edit the path specified in flake.nix within the modules array to point to ./modules/config.nix instead.

    flake.nix
    {
    # ...
    nixosConfigurations.YOURNAME = nixpkgs.lib.nixosSystem {
    # ...
    modules = [
    ./modules/config.nix
    ];
    };
    }

Importing other modules from config.nix

Now we need to tell NixOS what other files to load modules from.

To do this, in config.nix create a new array called imports (usually this is the very first config option).

This array should have the paths (relative to config.nix) of other modules to load.

modules/config.nix
{pkgs, ...}: {
imports = [./nix.nix ./graphics.nix ./shell.nix];
# ...
}

File Contents

Now fill in the modules we’ve created, use config.nix as reference, remember each module must return an attr set and are given a bunch of arguments. Here’s a good template for modules.

modules/some-module.nix
{pkgs, ...}: {
}

From there feel free to organize your source tree however you want!

Making nix.nix

I’ll leave exactly where to place certain options up to you, however this guide is going to require you to place the nix = { ... }; option inside modules/nix.nix, we’ll be importing it from somewhere else later.

  1. Remove the nix attr set from modules/config.nix.
    modules/config.nix
    {pkgs, ...}: {
    # ...
    nix = {
    channel.enable = false;
    package = pkgs.lix;
    settings = {
    experimental-features = [
    "nix-command"
    "flakes"
    ];
    auto-optimise-store = true;
    };
    gc = {
    automatic = true;
    dates = "weekly";
    };
    };
    # ...
    }
  2. Then add the attr set in modules/nix.nix.
    modules/nix.nix
    {pkgs, ...}: {
    nix = {
    channel.enable = false;
    package = pkgs.lix;
    settings = {
    experimental-features = [
    "nix-command"
    "flakes"
    ];
    auto-optimise-store = true;
    };
    gc = {
    automatic = true;
    dates = "weekly";
    };
    };
    }

Passing inputs to our configuration

So when I said there were only two methods to install software I kinda lied…

Nix flakes are a wonderful way to get software straight from the repo the software is hosted on. We can see in our flake.nix that we’re grabbing nixpkgs from GitHub.

flake.nix
{
inputs = {
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
};
# ...
}

Since NixOS uses nixpkgs already, it’s already passed to us as an argument to modules. However, there may come a time that we need to access other inputs within our modules.

In order to do this we have to tell NixOS additional arguments we want passed.

  1. On the line with outputs, add inputs @ before the {.
    flake.nix
    outputs = inputs @ {
    self,
    nixpkgs
    }: let
  2. Create a new attr set in our call to pkgs.lib.nixosSystem called specialArgs, we’ll want to inherit our inputs here.
    flake.nix
    nixosConfigurations.YOURNAME = pkgs.lib.nixosSystem {
    # ...
    specialArgs = { inherit inputs; };
    modules = [
    # ...
    ];
    }
  3. Now when we need to, we can specify inputs in our arguments on any module and have access to our flake inputs.
    modules/some-module.nix
    {inputs, pkgs, ...}: {
    # Access to flake inputs! Yay!
    }

This may not help much as our only inputs at the moment are self and nixpkgs, but as we add more this will come in handy.

Auto-formatting

This step is optional but I’d recommend it if you’re like me and enjoy consistent style in your code.

Another type of output a nix flake can provide is a formatter. This should be set to a package that has the ability to format Nix code, I’ll use alejandra (my personal preference) in this example.

To setup a formatter simply add it as an output to our flake.

flake.nix
outputs = inputs @ {
self,
nixpkgs
}: ... {
formatter.${system} = pkgs.alejandra;
# ...
}

Now we can format our code with Alejandra.

Terminal window
nix fmt