Skip to content

Instantly share code, notes, and snippets.

@jurraca
Created September 1, 2023 12:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jurraca/8202fa4cab37c123331a71113ce9db5a to your computer and use it in GitHub Desktop.
Save jurraca/8202fa4cab37c123331a71113ce9db5a to your computer and use it in GitHub Desktop.
Common Nix questions

I have code, I want to nix-ify it. How?

Make it a flake.

What's a flake?

This explanation from the Zero-to-Nix flake entry is good:

"A Nix flake is a directory with a flake.nix and flake.lock at the root that outputs Nix expressions that others can use to do things like build packages, run programs, use development environments, or stand up NixOS systems. If necessary, flakes can use the outputs of other flakes as inputs."

A flake is a directory, and makes most sense when that directory is also a git source tree. A flake declares three main values:

  • a description of the project (as a string)
  • inputs: what goes in
  • outputs: what goes out, i.e. a build, a development shell, etc

How do I make a package available via the Nix package manager?

You will need to write a Nix expression and add it to the Nixpkgs git repo. See here for the official contributing guide.

I want to use a custom version of a project in a development shell, but nixpkgs only has the main version (e.g. there's a fork of CLN, I want to include it in my project). What do I do?

You want an overlay. An overlay takes an existing Nix expression and overrides one or more attributes of that Nix expression. If you want to update the Git source of a project (for example, a custom fork), you could override the src attribute. You would then include this overlay expression in the overlays attribute of the pkgs attribute. Example:

This is a really useful pattern, allowing you to customize anything about other Nix packages.

See this short video by Jon Ringer illustrating the idea.

I thought Nix could target a variety of systems, why is it only building for my local system type?

Nix does enable this, but it's not magic, you have to tell it to build for different systems. In flakes, a common way of doing this is to use the flake-utils library, and its eachSystem and eachDefaultSystem functions, which take an attribute set and inject the system type in the expected flake format.

How do I add packages in the development shell that aren't required for the build itself?

Both the mkDerivation (and functions that may wrap it) and mkShell functions have a buildInputs attribute. You can specify what packages go in either the derivation and the development shell declaratively. It's common to include formatters, linters, and whatever dev tooling makes sense in the development shell and omit it from the build itself.

What's the difference in between a Nix expression and a flake?

A nix expression is a function which outputs anything really, and that usually depends on the Nixpkgs build instructions set in some way. If a Nix expression is included in a repo, it may or may not refer to local sources. You could for example refer to only external code in a Nix expression.
A flake is ALWAYS a directory, and often a git repo. It could refer to a local source along with other inputs, including potentially the nixpkgs set. I like to think of it as the next logical evolution of git version control, powered to handle builds and development and not just source version control.
Flakes are more composable since I can refer to other flakes as inputs into my flake. I can only do this with Nix expressions if they're available via a Nix package set, like Nixpkgs.

Can I refer to someone else's repository as a flake input?

Only if that external repository is a flake itself. You can't just refer to other git repos as flake inputs.

How am I supposed to refer to other people's repositories if they're not flakes?

Nix provides fetchers to get sources, such as fetchgit, fetchFromGitHub and fetchFromGitLab. These require a hash of the source tree to validate the contents of the repo. see the docs.

How do I fetch hashes for remote sources?

Either use lib.fakeSha256 to put a dummy hash, or fetch it ahead of time. When you run the build with a placeholder hash, it will fail and tell you the hash it received. Dumb but effective. Alternatively, use nix-prefetch-url, a handy utility to fetch the hashes of remote sources (see docs).

What's with the Nix hash formats?

Nix prefers SRI hashes, which specify the hash type as a prefix. For example: sha256-tWxnuVHhXl7JWwMxQ46b+Jd7PeoMVr7pnWXv5Of5AeI=. You can generate the sha256 SRI hash with the nix hash to-sri --type sha256 <my-hash> command. See docs.

What's with the myFunction = arg1: arg2: functionbody syntax?

Nix is curried. You can read this as def myFunction(arg1, arg2): functionbody. Damn Haskellers.

What attributes can a flake output consist of?

Here's a breakdown.

What's a devshell?

A development shell, also a flake output attribute. The idea is to give people a dev environment for your project with a simple nix develop command.

Can I play with a flake in a repl?

Yep. If you have flakes enabled, you can run nix repl, then :lf <flake-path>, i.e. "load flake ". this will load the flake inputs and outputs into your repl for you to inspect.

Where are the builtin Nix functions?

Here. These can be accessed in a Nix expression with builtins.<function-name>.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment