Trying to Wrap My Head Around Nix Packages – Where Do I Start?

Hey everyone,

I have been experimenting with NixOS for a bit now & while I appreciate the whole idea of reproducible builds and declarative configs, I am still struggling to get comfortable with how package development actually works in Nix.

Also I have tried reading the manual & looked at a few community flakes & GitHub repos but I am still fuzzy on how mkDerivation works in practice, when it comes to layering or overriding packages. Also, is there a clean way to set up a development shell without pulling in too much?

I found ReactJS Training tutorials easier to follow than this—maybe because there are more video walk-throughs or interactive examples. Is there anything similar out there for Nix?

I want to hear how some of you approached learning this & if you have tips or personal workflows to share for testing packages locally without messing up your system setup.
Also i have check this Flake error when trying to build the system: packages.x86_64-linux.nixosConfigurations.”nixos”.config.system.build.nixos-rebuild’ I want to know more.

Thank you.:slight_smile:

I recommend studying https://nix.dev.

2 Likes

You can’t mess up your system by developing packages, unless you include those packages in your system configuration, otherwise they are just paths in the store.

Can you be more specific about what you are struggling with? Which manual did you read? Have you gone through the material at https://nix.dev? What do you know about packaging in general? Have you tried to develop a package? If so do you have the workings, where did you get stuck? If you want something more specific about mkDerivation have you tried reading the nix pills?

My recommendation always is to play with the repl, it is criminally underrated in general for getting to grips with things, especially pkgs.writeShellScript and friends (you can find them in noogle or the manual). You can get a lot done!

❯ nix repl --file '<nixpkgs>'
Nix 2.28.3
Type :? for help.
Loading installable ''...
Added 24753 variables.
nix-repl> myconfig = pkgs.writeText "my-config" '' 
            [general]  
            some_key=some_value
          ''

nix-repl> mywrapper = pkgs.writeShellScriptBin "my-wrapper" ''
            echo exec mywrappedexe --config ${myconfig}
          ''

nix-repl> :b mywrapper

This derivation produced the following outputs:
  out -> /nix/store/appxa6ghjhcaz690nc5ivn04kpp027jc-my-wrapper



~ took 1m22s 
❯ /nix/store/appxa6ghjhcaz690nc5ivn04kpp027jc-my-wrapper/bin/my-wrapper 
exec mywrappedexe --config /nix/store/wd1xzv6w4i91wxs1qkfksglqj37w7zvi-my-config

~ 
❯ cat /nix/store/wd1xzv6w4i91wxs1qkfksglqj37w7zvi-my-config
[general]
some_key=some_value

If the above wasn’t clear this was me trying to demo a pretty common idea of making shell scripts, linking in config etc, all by composing trivial builders. You can also experiment with fetching in the same way. Lets say I wanted to get tigerbeetle on my current system. You can repl hack your way pretty far:

~ took 1m41s 
❯ nix-hash --to-base64 --type sha256 (nix-prefetch-url https://github.com/tigerbeetle/tigerbeetle/releases/download/0.16.46/tigerbeetle-x86_64-linux.zip)
path is '/nix/store/09g5flbhh3rbqkiw6ba8fb5ba3bn16pz-tigerbeetle-x86_64-linux.zip'
sBtAfRWOOiZWhcMIzkebAMhu4/AuEmlzjUJVb1rBLfs=

~ 
❯ nix repl --file '<nixpkgs>'
Nix 2.28.3
Type :? for help.
Loading installable ''...
Added 24753 variables.
nix-repl> src = pkgs.fetchurl { url = "https://github.com/tigerbeetle/tigerbeetle/releases/download/0.16.46/tigerbeetle-x86_64-linux.zip"; hash = "sha256-sBtAfRWOOiZWhcMIzkebAMhu4/AuEmlzjUJVb1rBLfs="; }

nix-repl> :b pkgs.runCommand "tigerbeetle" { buildInputs = [ pkgs.unzip ]; } ''               
               mkdir $out                                                                     
               unzip ${src} -d $out/bin                                                       
             ''

This derivation produced the following outputs:
  out -> /nix/store/2zgdrmb3b7az81f4xi8nsbvwplpxjpbp-tigerbeetle



~ took 26s 
❯ lt /nix/store/2zgdrmb3b7az81f4xi8nsbvwplpxjpbp-tigerbeetle
/nix/store/2zgdrmb3b7az81f4xi8nsbvwplpxjpbp-tigerbeetle
└── bin
    └── tigerbeetle

~ 
❯ /nix/store/2zgdrmb3b7az81f4xi8nsbvwplpxjpbp-tigerbeetle/bin/tigerbeetle --help
Usage:

  tigerbeetle [-h | --help]

  tigerbeetle format [--cluster=<integer>] --replica=<index> --replica-count=<integer> <path>

  tigerbeetle start --addresses=<addresses> [--cache-grid=<size><KiB|MiB|GiB>] <path>

  tigerbeetle recover --cluster=<integer> --addresses=<addresses>
                      --replica=<index> --replica-count=<integer> <path>

Obviously this isn’t a good derivation (doesn’t respect the platform to start with), but I think you can probably see how this is a useful muscle to work for understanding how nix composes store path manipulations. Once you’ve got this locked in, reading the stdenv docs in the nixpkgs manual should make a lot more sense.