This post aims to be a collection of useful tips & tricks that I've learnt over the years of using Nix & NixOS.

What is Nix*?

The Nix ecosystem has a lot of overloaded terms:

How do these relate to each other?

  • The Nix package manager uses the Nix language to define packages and interact with Nixpkgs.
  • The NixOS operating system uses the Nix language and the Nix package manager to define an immutable operating system.
  • Nixpkgs is a repository of Nix packages and software modules: build definitions of software and software services, written in the Nix language.

Advice on using Nix

You don't have to understand everything

2 years in, I still don't understand every detail of how Nix or NixOS work. My experience is somewhat like being an expat in a foreign country.

I have embraced the country fully and live there full-time, I can understand the spoken language somewhat well, I can understand the written language well, and I can make myself understood with some trouble.

In computer terms; I use Nix(OS) everywhere I can, I can read Nix code and understand what it does pretty well, and I can write my own Nix derivations by using existing references as starting points. But I can't read or write things fluently without using any reference materials.

Consult with references

  • Keep a local copy of nixpkgs and use rg or grep to find existing examples for things you want to understand better, such as NixOS services or Nixpkgs helper functions.
  • If you use NixOS, keep track of other people's system configurations to learn how they structure their environments.
  • Consult the NixOS manual on how to install NixOS and on some explanations for various configuration settings.
  • Read and follow along with the Nix Pills to understand how Nix derivations work and how to write them.
  • Consult the Nix Reference Manual on anything related to how Nix works.

Use flakes

At the time of writing, this is still an experimental feature. However, it is the sane approach to Nix - I haven't even bothered learning how you would use Nix without flakes.

The corollary advice of using flakes is to avoid nix-env and nix-channel.

Use Home Manager

Home Manager is the Nix approach of maintaining user-level dotfiles.

You don't really need it if you only have one user, but still I find that it's been very pleasant to use even for single-user systems.

Use direnv

Direnv lets you automatically source your developer environments when you cd into them. Works beautifully in conjunction with flake.nix or default.nix.

# Without flakes
echo "use nix" >> .envrc && direnv allow

# With flakes
echo "use flake" >> .envrc && direnv allow

Using flakes without checking flake.nix and lock.nix into Git

A controversial design choice of Nix flakes is that they require to be checked in with your source - or at least added (not necessarily commited).

This can make it painful to use when collaborating on projects that don't want to have these files checked in.

The solution I've found here is to use a parent directory with a dummy Git project.

├── actual-project/
├── .direnv/
├── .envrc
├── flake.nix
└── lock.nix

So when you cd into dummy-parent or actual-project, you will activate the developer environment specified in flake.nix without actual-project being aware of your Nix configuration.

Maintain multiple devices with one configuration

As of August 2023, I maintain the following devices with the same base configuration:

  1. Home network router (see Building a Router with NixOs)
  2. NAS for private storage & services
  3. Stationary gaming PC
  4. Macbook Air M2
  5. Macbook Pro M2 (for work)
  6. Samsung Ativbook 9+ (old scrappy laptop for travel etc)

These are all configured by this configation. Common things, like how I want Neovim or Tmux to behave, are defined in modules that all of these systems use.

Stuff like kernel boot parameters are specified individually for each system. Linux systems run NixOS, Mac systems run MacOS with Nix Darwin.

Having one configuration that dictates how all my devices behave is truly freeing.