What do I need to know to use nix and where to find more? A concise overview for new users

I made this reddit comment, and some people thought it deserved its own post so here I am. Im just going to jump right into it.

Ok. So, first thing. The packages in nix are called derivations and are like mini filesystems, i.e. they have a /bin folder a /lib folder a /share folder etc. These all get linked together to form an environment which becomes your path, includes, and things like that. For example, every derivation added to environment.systemPackages has its bin directory added to your system PATH

You should become comfortable with this concept, and with the basic nix language, and the command line commands

https://nixos.org/manual/nix/stable/language/

https://nixos.org/manual/nix/stable/command-ref/new-cli/nix

Second things, just as important:

Learn the difference between a flake, a module, and an expression.

The options you set in your config such as services.xserver.desktopManager.xfce.enable come from modules in nixpkgs. Your config file itself is also a module, and it can import other modules that you create or find online. Modules in nixpkgs basically just put things in environment.systemPackages for you, or link store paths to places such as /etc and /boot (which are themselves also module options) but with appropriate settings, and they define a few relevant options for you to change their behavior as you wish. You should get used to modules, as they will be your main method of organizing your own config, and you may even want to define your own module options for yourself to use as well, such as for machine specific configuration.

Flakes are just a more declarative (and in my opinion, easier to use) way to import a channel, as the import of said channel is within your config as opposed to importing your channel separately from config via imperative command. They simply wrap a normal config made up of modules and expressions in a more declarative and complete way. You should only have 1 flake.nix file per repo and you can think of it kinda as your repos “main()” function (except it cant take arguments, you can only build the attributes you define in its output as they are). While maybe being a liiittle slower to build, flakes drastically improve the ease of use of controlling your nixpkgs version, and make things easier and more reproducible across machines and reinstalls in almost every case. You should use them. Again, you only need 1 flake.nix file in your repo, and it just wraps as many normal machine configs/programs/shells/etc. as you want in a cohesive way, allowing you to have 1 repo for all of them in an organized way, and share code between them, reducing duplication.

Expressions are just files containing nix code that you can import with the import command. They can be a function, a set, and things like that. Basically if it is a .nix file and isnt a module or a flake, its an expression.

These 2 and the difference between them is a thing you should understand:

https://nixos.wiki/wiki/NixOS_modules

https://nixos.wiki/wiki/Flakes

For searching packages and available module options:

NixOS Search?

NixOS Search?

And home manager module options:

https://home-manager-options.extranix.com/

Home manager is an extra, optional tool for managing user level files. Its modules are exactly the same as nixos modules, except they have different options. i.e. home.packages instead of environment.systemPackages

You will also want to know about the lib functions and trivial builders as they are your bread and butter for writing basic scripts and files to the store outside of the builtins. For example, builtins.toFile cannot contain derivation paths, but pkgs.writeTextFile can.

https://ryantm.github.io/nixpkgs/functions/library/lists/

https://ryantm.github.io/nixpkgs/builders/trivial-builders/

You should not be scared of learning to read the source code of a module when you use it. Modules are (usually) quite readable. Each option it defines will have the relevant docstring for it in the code, and below them, you can see the config set, which is where it sets the config based on the option values, the same way you would in your original config file, but with options. The sooner you learn to do this, the easier of a time you will have setting things up as you like them. Your originally generated config file is just a module but without an options set (a useful shorthand for modules that dont set options for other modules to use).

Likewise, when trying to import a flake, you should go to its flake.nix and see what things it outputs in its output function in order to figure out how to import it (if the docs do not make it clear).

Reading source code of package derivations themselves is rarely necessary. If they contain an executable, its in that packages bin folder. Thats about all you need to know to get started using them, and creating wrapper scripts to start them with nix defined configurations. But later, you can also learn to override specific attributes they contain to have very fine control over them.

In addition to the above, many people find Nix Pills to be a useful resource.

Also, as a tip, all your script shebangs should either be added with pkgs.writeShellScript or pkgs.writeShellScriptBin in your nix config, OR if the script is not created inside your config but is just a file, then you should make the shebang be

#!/usr/bin/env bash

This is particularly useful when you realize you can add pkgs.writeShellScriptBin to environment.systemPackages, and do

environment.systemPackages = (let

   alakitty-toml = pkgs.writeText "alacritty.toml" ''
    [shell]
    program = "${pkgs.zsh}/bin/zsh"
    args = [ "-l" ]

    [font]
    size = 11.0

    [font.normal]
    family = "FiraMono Nerd Font"
    style = "Regular"
   '';

   alakitty = pkgs.writeShellScriptBin "alacritty" ''
     exec ${pkgs.alacritty}/bin/alacritty --config-file ${alakitty-toml} "$@"
   '';

in [
  alakitty
]);

Which is pretty cool. You put alakitty in environment.systemPackages and Alacritty isnt installed to your path. alakitty is. You launch it with alacritty though.

For running externally compiled binaries that are giving you troubles with unfound libraries, you may wish to look into the programs.nix-ld module options to provide those libraries to the program.

7 Likes

I’m sure these kinds of high level recaps will be very useful. I wonder how that can be contributed to nix.dev !

I am not part of the documentation team, but maybe worth posting a contribution?

1 Like