Part 1: Nix, Flakes & Nix
DevShell
Gabriel Nützi, gabriel.nuetzi@sdsc.ethz.ch
Cyril Matthey-Doret, cyril.matthey-doret@epfl.ch
May 8, 2025 (Updated: Sep 3, 2025), Repository, Slides
How to use these slides:
Thanks to the following contributors:
Cyril Matthey-Doret for reviewing the initial draft.
SDSC ORDES Team for feedback.
Farid Zakaria for giving the talk at PlanetNix 2025 which we integrated into this talk.
The Nix Community at
All examples refer to the workshop repository in the root directory.
Ensure that you have the requirements fulfilled.
You start python
and you get this:
>>> import numpy
Segmentation fault (core dumped)
Feature | Local Development | Mamba | Devcontainer | Nix/DevShell |
---|---|---|---|---|
Maintainenance | ⚠️ High | ⚠️ Medium | ⚠️ Medium | ⚠️ Medium |
Reproducibility | ❌ Low | ⚠️ Medium | ⚠️ Medium | ✅ Very high |
Ease of Use | ❌ Low | ✅ Easy | ✅ Ok | ❌ Low |
Dep. Mgmt. | ❌ | ✅ | ⚠️ | ✅ |
Portability | 💣 | ⚠️ | ✅ | ✅ |
CI Stability | 💣 | ⚠️ | ⚠️ | ✅ Almost Perfect |
Nix is a software package management & deployment infrastructure:
🏃🏻♂️Software is built and run in a predictable and reproducible way.
✅ Builds are reproducible — same inputs give same results.
🔄 Installs packages without breaking others.
📦 Can create isolated dev environments.
💻 Works on Linux, macOS.
I am building a script to find my IP:
#! /usr/bin/env bash
curl -s http://ipinfo.io | jq --raw-output .ip
12.24.14.88
What guarantees that jq
or curl
is
available?
{
system ? builtins.currentSystem,
pkgs ?
import
(builtins.fetchTarball "https://github.com/NixOS/nixpkgs/archive/9684b53175fc6c09581e94cc85f05ab77464c7e3.tar.gz")
{
inherit system;
},
}:
pkgs.writeShellScriptBin "what-is-my-ip"
''
${pkgs.curl}/bin/curl -s http://ipinfo.io | \
${pkgs.jq}/bin/jq --raw-output .ip
''
Building this Nix code gives you a store path:
/nix/store/7x9hf9g95d4wjjvq853x25jhakki63bz-what-is-my-ip
which contains the script and all needed dependencies
#!/nix/store/mc4485g4apaqzjx59dsmqscls1zc3p2w-bash-5.2p37/bin/bash
/nix/store/zl7h70n70g5m57iw5pa8gqkxz6y0zfcf-curl-8.12.1-bin/bin/curl \
-s "http://ipinfo.io" | \
/nix/store/y50rkdixqzgdgnps2vrc8g0f0kyvpb9w-jq-1.7.1-bin/bin/jq \
--raw-output ".ip"
Nix has encoded the used executables with
store paths (/nix/store
).
/nix/store/7x9hf9g95d4wjjvq853x25jhakki63bz-what-is-my-ip
The hash 7x9hf9g95d4wjjvq853x25jhakki63bz
of your built
package depends on:
curl
, jq
)nix
code,
including dependencies)⛓️ Deterministic software packaging.
Domain-specific functional language (no side-effects).
Structurally similar to JSON but with functions.
Fundamental data types such as string
,
integer
, path
, list
, and
attribute set
.
Lazy Evaluated: expression evaluation delayed until needed.
⚠️Specifically designed for deterministic/reproducible software deployment.
Nix files *.nix
- contain mostly
one function.
The function below takes one argument
banana
and returns an attribute set
{ x = ... }
:
# myfunction.nix
banana: # Function with one argument `banana`.
let # Define variables.
number = 1; # A number.
list = [ 1 2 3 "help"]; # A list with 4 elements.
set = { a = 1; b.c.d = [1]; }; # A nested attribute set.
result = banana.getColor { v = number; }; # Calls another function `banana.getColor`.
in
{ x = number; y = set.b.c.d; z = result; } # Return an attribute set.
For later: Watch this short introduction.
let # start for "procedural" statements
mult = a: b: a * b;
mult10 = mult 10; # Bind the first arg.
in
mult10 (mult 8 2)
# -> 160
let
f = args: {
a = args.banana + "-nice";
b = args.orange + "-sour";
};
in
f { banana = "1"; orange = "2" }
# -> { a = "1-nice"; b = "2-sour"; }
let
f = { ban, ora, ... }: { # Destructuring
a = ban + "-nice";
b = ora + "-sour";
};
in
f { ban = "1"; ora = "2"; berry ="3"; }
# -> { a = "1-nice"; b = "2-sour"; }
let
f = { list ? [] }: {
a = builtins.map (x: x*x) list;
};
in f [ 1 3 9 ]
# -> { a = [ 1 9 81 ] }
# Concat lists.
[ 1 2 3 ] ++ [ 1 2 3 ]
# [ 1 2 3 1 2 3 ];
# Merge attribute sets.
{ a = 1; b = 2; } // { a = 2; c = 3; }
# -> { a = 2; b = 2; c = 3; }
rec {
b = 2;
c = b + d;
d = 10;
} # Discouraged: prefer `inherit`.
# -> { b = 2; c = 12; d = 10; }
# Lazy evaluation.
let
x = abort "fail";
in
if true then 42 else x
# -> 42
# Import files.
let
myfunc = import ./myfunction.nix;
in myfunc 1 + (import ./other.nix 3)
inherit
# Inherit 'key = value'.
let
width = 100;
color = "blue";
set = { b = 1; };
in
{
inherit color; # color = color;
inherit (set) b; # b = set.b;
}
let
key = "c"
color = "blue";
set = {
c = { v = "hello-${color}" ;}
};
in set.${key}.v
# -> "hello-blue"
let
dir = ./.github/workflows; # A path. Nix makes them absolute!
file = "${dir}/gh-pages.yaml"; # Interpolated path gets added into the `/nix/store`.
in file
# -> "/nix/store/w9il9gvki2nfdzfc1lrlbiv3xy3mx90a-workflows/gh-pages.yaml"
let
StatementsDo not reassign in let
blocks:
let
a = "hello";
a = a + "world";
# ^
# |
# 🆘 Endless recursion, this is not reassigning.
in a
✅ Configure nixd
(Nix Language Server) in your IDE
to see “Go to definitions”.
Try out the examples shown before yourself with nix repl
(see slide)
Verify in the interactive Nix shell:
nix repl
Or pass standard input to nix eval
:
echo 'let a = 3; in a' | nix eval --file -
Time: 3min
whats-is-my-ip
Put the following in a script whats-is-my-ip.nix
:
let
system = builtins.currentSystem; # e.g. `x86_64-linux`
# Download something into the `/nix/store/...-source`
src = builtins.fetchTarball
"https://github.com/NixOS/nixpkgs/archive/9684b53175fc6c09581e94cc85f05ab77464c7e3.tar.gz";
# Import the `default.nix` in the `/nix/store/...-source`
f = import src;
pkgs = f { inherit system; }; # This is the package attribute set of `nixpkgs`.
in
pkgs.writeShellScriptBin "what-is-my-ip" ''
${pkgs.curl}/bin/curl -s http://ipinfo.io | \
${pkgs.jq}/bin/jq --raw-output .ip
''
github.com/NixOS/nixpkgs
? nixpgkgs
is a mono-repository with Nix
code to build software packages (> 130k).
A commit in nixpkgs
represents the
version of all packages at that
commit (a big tree).
github.com/NixOS/nixpkgs
?Statement f = import src;
imports default.nix
from nixpkgs
[1]
f
.pkgs
for your system
(e.g
"x86_64-linux"
).Package Search:
Function Search: https://noogle.dev.
nix build -f ./examples/what-is-my-ip.nix --print-out-paths
> "/nix/store/7x9hf9g95d4wjjvq853x25jhakki63bz-what-is-my-ip"
Explore whats in
/nix/store/7x9hf9g95d...-what-is-my-ip/bin/what-is-my-ip
:
#!/nix/store/mc4485g4apaqzjx59dsmqscls1zc3p2w-bash-5.2p37/bin/bash
/nix/store/zl7h70n70g5m57iw5pa8gqkxz6y0zfcf-curl-8.12.1-bin/bin/curl \
-s "http://ipinfo.io" | \
/nix/store/y50rkdixqzgdgnps2vrc8g0f0kyvpb9w-jq-1.7.1-bin/bin/jq \
--raw-output ".ip"
pkgs.writeShellScriptBin "what-is-my-ip" ''
${pkgs.curl}/bin/curl -s http://ipinfo.io | \
${pkgs.jq}/bin/jq --raw-output .ip
''
pkgs.writeShellScriptBin
is a trivial builder
function around the derivation
command (see
appendix).Run
nix-store --query --include-outputs --graph \
$(nix build -f ./examples/what-is-my-ip.nix --print-out-paths) > graph.dot
nix develop --command dot -Grankdir=TB -Gconcentrate=true -Tpng graph.dot > graph.png
and inspect graph.png
.
You have seen files like flake.nix
lying around in
repositories already.
provides a deterministic way to manage dependencies and configurations [1].
comes with a flake.lock
file which
locks dependencies.
Remember fetchTarball ".../NixOS/nixpkgs/..."
in what-is-my-ip.nix
.
🌻 A flake.nix
is a better method for locked inputs.
A flake flake.nix
:
# flake.nix
{
inputs = { /* ... */ };
outputs = inputs: {
packages = /* implementation */
# ... other output attributes ...
}
}
Nix evaluates a flake.nix
by
calling the outputs
with inputs
.
Try nix repl
and :lf .
to load the ./flake.nix
in directory
.
.
Check
outputs.packages.x86_64-linux = { ... }
.
Flat attribute set of Nix derivations.
Note: Certain output attributes are system
scoped, e.g. packages.x86_64-linux
.
A derivation is a
specialized attribute set, describes how to build a Nix package.
{ type = "derivation"; ... }
Check nix repl -f <nixpkgs>
and type
pkgs.curl.type
.
A derivation is a build instruction to realize a package in the
/nix/store
using a specialderivation
function.
- Can depend on multiple other derivations.
- Produce one or more outputs.
The complete set of dependencies required to build a derivation—including its transitive dependencies—is called a closure. [Ref]
Evaluating: Store build
instructions in the /nix/store
(a store derivation
*.drv
, more details).
Building: Realizing outputs of
the derivation in the /nix/store
. This can literally be
anything!
Build the example derivation - eval. & realize it in the Nix store:
cd nix-workshop
nix build -L "./examples/flake-simple#packages.x86_64-linux.mytool" \
--print-out-paths --out-link ./mytool
or in steps see appendix.
ℹ️ The string
./examples/flake-simple#packages.x86_64-linux.mytool
is
called an installable (see appendix).
🩳 Short Form:
nix build "./examples/flake-simple#mytool"
uses
builtins.currentSystem
(works also for macOS
users).
✅ Inspect tree ./mytool
:
/nix/store/blm702jzc...vd9gxp4c9n-mytool
└── bin
└── mytool
✅ Run it with:
./mytool/bin/mytool -h
nix run "./examples/flake-simple#mytool"
You can also specify github
repositories and nested
flakes and build/run derivations on them:
nix build -L "github:sdsc-ordes/nix-workshop?dir=examples/flake-simple#mytool"
nix run "github:sdsc-ordes/nix-workshop?dir=examples/flake-simple#mytool"
Its a Nix derivation in the output attribute set
devShells
of the flake.nix
:
{
inputs = { /* ... */ };
outputs = inputs: {
packages.x86_64-linux = {
mytool = /* derivation */
};
devShells.x86_64-linux = {
banana-shell = /* derivation */
};
# ... other outputs ...
}
}
The banana-shell
derivation is meant to be consumed by
nix develop
.
The flake in ./examples/flake-simple
defines
devShells
an output:
devShells.x86_64-linux =
let pkgs = inputs.nixpkgs-unstable.legacyPackages.${system}; in
{
default = pkgs.mkShell {
packages = [ pkgs.skopeo pkgs.cowsay ];
shellHook = ''
echo "Hello from Shell"
${pkgs.cowsay}/bin/cowsay
'';
};
}
);
Function pkgs.mkShell
makes a derivation consumable by
nix develop
:
nix develop "github:sdsc-ordes/nix-workshop?dir=examples/flake-simple#default" --command zsh
devenv.sh
for Nix DevShells🚧 Nix DevShells from nixpkgs
(pkgs.mkShell
) are raw and too
simplistic.
🌻Nix DevShells from devenv.sh
provides more concise
configuration.
NixOS
(NixOS Modules).Time to get 🫵r fingers dirty with the following exercises:
flake.nix
for a Go
project.forAllSystems
.devenv
for a run-it
script [optional].Follow the steps in examples/flake-go/README.md
.
🦸Devenv Nix Shell is deterministic/reproducible and with lots of power.
Foundation of a flake.nix
and integration of a Nix
shell. Simpler approach with devenv.nix
.
Nix community is flourishing - contribute or support it:
We maintain well-structured, state-of-the-art,
nix
-enabled repository templates for toolchains
like:
The templates provide CI out of the box and are ready to use!
🌍 Tackling non-reproducible software distribution is hard — but essential
🚀 Embrace Nix to gain
🤝 The Nix community is welcoming and supportive — don’t hesitate to ask!
✅ Check the references/resources provided (🤷♀️ sometimes its a mess, but gets better).
Solutions in the notes.
what-is-my-ip.nix
on your machine in the workshop repository.Time: 15-20min
Quiz: What do you expect
/nix/store/zl7h70n70g5m57iw5pa8gqkxz6y0zfcf-curl-8.12.1-bin/bin/curl
links to and what does your system curl
link to?
Use ldd
to inspect.
Load the flake
in the the root directory in nix repl
and use
:lf .
inputs.nixpkgs
."${inputs.nixpkgs}"
and explore the
output!import "${inputs.nixpkgs}" { system = "x86_64-linux"; }
.Eval/build/run the treefmt
utility in the
packages
output in the flake inside the root directory.
Hints:
nix eval --impure --expr 'builtins.currentSystem'
packages.${system}.treefmt
nix run
"github:sdsc-ordes/nix-workshop#..."
Time: 15-20min
./examples/flake-simple
to include your
package from nixpkgs
.Time: 5 min
In maths a fix point x
of a function F
is
defined as:
\[ x = F(x). \]
In functional programming a fix-point combinator
fix
is a higher-order function.
It returns the
fix point of a function F
:
fix = F: let x = F x in x
That is how recursive self-referential sets can be defined.
let
fix = F: let x = F x in x;
# Define the constructor of the set.
newSet = self: { path = "/bin"; full = self.path + "/my-app"; };
mySet = fix newSet; # fulfills: mySet == fix mySet;
in
mySet.full
Seems recursive in let x = F x
but but isn’t
🤯, because its lazy evaluated. What you need to know about laziness..
Used in pkgs.callPackage
in nixpkgs
.
The choice for lazy evaluation allows us to write Nix expressions in a convenient and elegant style: Packages are described by Nix expressions and these Nix expressions can freely be passed around in a Nix program – as long as we do not access the contents of the package, no evaluation and thus no build will occur. […] At the call site of a function, we can supply all potential dependencies without having to worry that unneeded dependencies might be evaluated. For instance, the whole of the Nix packages collection is essentially one attribute set where each attribute maps to one package contained in the collection. It is very convenient that at this point, we do not have to deal with the administration of what exactly will be needed where. Another benefit is that we can easily store meta information with packages, such as name, version number, homepage, license, description and maintainer. Without any extra effort, we can access such meta-information without having to build the whole package. [Paper]
derivation
This is what pkgs.writeShellScriptBin
would expand to:
(see ./examples/what-is-my-ip-orig.nix):
derivation {
inherit system;
name = "what-is-my-ip";
builder = "/bin/sh";
args = [
"-c"
''
${pkgs.coreutils}/bin/mkdir -p $out/bin
{
echo '#!/bin/sh'
echo '${pkgs.curl}/bin/curl -s http://ipinfo.io | \
${pkgs.jq}/bin/jq --raw-output .ip'
} > $out/bin/what-is-my-ip
${pkgs.coreutils}/bin/chmod +x $out/bin/what-is-my-ip
''
];
outputs = [ "out" ];
}
A store derivation (
*.drv
) contains only build instructions for Nix to realize/build it. This can be literally anything, e.g. a software package, a wrapper shell script or only source files.
# Evaluate it.
drvPath=$(nix eval "./examples/flake-simple#packages.x86_64-linux.mytool" --raw)
# Realize it.
nix build -L "$drvPath" --print-out-paths --out-link ./mytool
nix eval "./examples/flake-simple#packages.x86_64-linux.mytool"
> «derivation /nix/store/l8pma77py04gd5819zkk3h7jx0bgxqgm-mytool.drv»
./examples/flake-simple#packages.x86_64-linux.mytool
is
an installable. More later!
# Inspect the store derivation.
cat /nix/store/l8pma77py04gd5819zkk3h7jx0bgxqgm-mytool.drv
> Derive([("out","/nix/store/5rvqlxk2vx0hx1yk8qdll2l8l62pfn8n-treefmt","","")],
[("/nix/store/1fmb3b4cmr1bl1v6vgr8plw15rqw5jhf-treefmt.toml.drv",["out"]),
("/nix/store/3avbfsh9rjq8psqbbplv2da6dr679cib-treefmt-2.1.0.drv",["out"]),
("/nix/store/61fjldjpjn6n8b037xkvvrgjv4q8myhl-bash-5.2p37.drv",["out"]),
("/nix/store/gp6gh2jn0x7y7shdvvwxlza4r5bmh211-stdenv-linux.drv",["out"])]
,["/nix/store/v6x3cs394jgqfbi0a42pam708flxaphh-default-builder.sh"]
,"x86_64-linux","/nix/store/8vpg72ik2kgxfj05lc56hkqrdrfl8xi9-bash-5.2p37/bin/bash",
["-e","/nix/store/v6x3cs394jgqfbi0a42pam708flxaphh-default-builder.sh"],
[ ("__structuredAttrs",""),("allowSubstitutes",""),
("buildCommand","target=$out/bin/treefmt\nmkdir -p \"$(dirname \"$target\")\"\n\nif [ -e \"$textPath\" ]; then\n mv \"$textPath\" \"$target\"\nelse\n echo -n \"$text\" > \"$target\"\nfi\n\nif [ -n \"$executable\" ]; then\n chmod +x \"$target\"\nfi\n\neval \"$checkPhase\"\n"),("buildInputs",""),("builder","/nix/store/8vpg72ik2kgxfj05lc56hkqrdrfl8xi9-bash-5.2p37/bin/bash"),("checkPhase","/nix/store/8vpg72ik2kgxfj05lc56hkqrdrfl8xi9-bash-5.2p37/bin/bash -n -O extglob \"$target\"\n"),("cmakeFlags",""),("configureFlags",""),("depsBuildBuild",""),("depsBuildBuildPropagated",""),("depsBuildTarget",""),("depsBuildTargetPropagated",""),("depsHostHost",""),("depsHostHostPropagated",""),("depsTargetTarget",""),("depsTargetTargetPropagated",""),("doCheck",""),("doInstallCheck",""),("enableParallelBuilding","1"),("enableParallelChecking","1"),("enableParallelInstalling","1"),("executable","1"),("mesonFlags",""),("name","treefmt"),("nativeBuildInputs",""),("out","/nix/store/5rvqlxk2vx0hx1yk8qdll2l8l62pfn8n-treefmt"),("outputs","out"),("passAsFile","buildCommand text"),("patches",""),("preferLocalBuild","1"),("propagatedBuildInputs",""),("propagatedNativeBuildInputs",""),("stdenv","/nix/store/hsxp8g7zdr6wxk1mp812g8nbzvajzn4w-stdenv-linux"),("strictDeps",""),("system","x86_64-linux"),("text","#!/nix/store/8vpg72ik2kgxfj05lc56hkqrdrfl8xi9-bash-5.2p37/bin/bash\nset -euo pipefail\nunset PRJ_ROOT\nexec /nix/store/0jcp33pgf85arjv3nbghws34mrmy7qq5-treefmt-2.1.0/bin/treefmt \\\n --config-file=/nix/store/qk8rqccch6slk037dhnprryqwi8mv0xs-treefmt.toml \\\n --tree-root-file=.git/config \\\n \"$@\"\n\n")])
JSON output of the above:
nix derivation show /nix/store/l8pma77py04gd5819zkk3h7jx0bgxqgm-mytool.drv
{
"/nix/store/l8pma77py04gd5819zkk3h7jx0bgxqgm-mytool.drv": {
"args": [
"-e",
"/nix/store/vj1c3wf9c11a0qs6p3ymfvrnsdgsdcbq-source-stdenv.sh",
"/nix/store/shkw4qm9qcw5sc5n1k5jznc83ny02r39-default-builder.sh"
],
"builder": "/nix/store/9nw8b61s8lfdn8fkabxhbz0s775gjhbr-bash-5.2p37/bin/bash",
"env": {
"__structuredAttrs": "",
"allowSubstitutes": "",
"buildCommand": "target=$out/bin/mytool\nmkdir -p \"$(dirname \"$target\")\"\n\nif [ -e \"$textPath\" ]; then\n mv \"$textPath\" \"$target\"\nelse\n echo -n \"$text\" > \"$target\"\nfi\n\nif [ -n \"$executable\" ]; then\n chmod +x \"$target\"\nfi\n\neval \"$checkPhase\"\n",
"buildInputs": "",
"builder": "/nix/store/9nw8b61s8lfdn8fkabxhbz0s775gjhbr-bash-5.2p37/bin/bash",
"checkPhase": "/nix/store/9nw8b61s8lfdn8fkabxhbz0s775gjhbr-bash-5.2p37/bin/bash -n -O extglob \"$target\"\n",
"cmakeFlags": "",
"configureFlags": "",
"depsBuildBuild": "",
"depsBuildBuildPropagated": "",
"depsBuildTarget": "",
"depsBuildTargetPropagated": "",
"depsHostHost": "",
"depsHostHostPropagated": "",
"depsTargetTarget": "",
"depsTargetTargetPropagated": "",
"doCheck": "",
"doInstallCheck": "",
"enableParallelBuilding": "1",
"enableParallelChecking": "1",
"enableParallelInstalling": "1",
"executable": "1",
"mesonFlags": "",
"name": "mytool",
"nativeBuildInputs": "",
"out": "/nix/store/blm702jzcwfppwrrj9925ivd9gxp4c9n-mytool",
"outputs": "out",
"passAsFile": "buildCommand text",
"patches": "",
"preferLocalBuild": "1",
"propagatedBuildInputs": "",
"propagatedNativeBuildInputs": "",
"stdenv": "/nix/store/npp9k9062ny7w0k1i03ij6xvqb7vhvjh-stdenv-linux",
"strictDeps": "",
"system": "x86_64-linux",
"text": "#!/nix/store/9nw8b61s8lfdn8fkabxhbz0s775gjhbr-bash-5.2p37/bin/bash\n\"/nix/store/xkk1gr9bw2dbdjna8391rj1zl1l3dmhq-cowsay-3.8.4/bin/cowsay\" \"Hello there ;)\"\necho \"-------------------------------------\"\n\"/nix/store/4ydiim4lfk6nyab4pdkjj9s33pgbigfd-figlet-2.2.5/bin/figlet\" \"Do you expect\"\n\"/nix/store/4ydiim4lfk6nyab4pdkjj9s33pgbigfd-figlet-2.2.5/bin/figlet\" \"something \"\n\"/nix/store/4ydiim4lfk6nyab4pdkjj9s33pgbigfd-figlet-2.2.5/bin/figlet\" \"useful ? \"\n\n"
},
"inputDrvs": {
"/nix/store/1fsd2cb5ab7ci01ks4j0gbbq254jw6sk-stdenv-linux.drv": {
"dynamicOutputs": {},
"outputs": ["out"]
},
"/nix/store/lrf9kbhlaf5mkvnlf3zr9wzvk7c2z72l-bash-5.2p37.drv": {
"dynamicOutputs": {},
"outputs": ["out"]
},
"/nix/store/phq4wh4490manblg905xixpc3gvwr149-figlet-2.2.5.drv": {
"dynamicOutputs": {},
"outputs": ["out"]
},
"/nix/store/wdpicivrj0bmzh935rr1hm1vlk18j0mp-cowsay-3.8.4.drv": {
"dynamicOutputs": {},
"outputs": ["out"]
}
},
"inputSrcs": [
"/nix/store/shkw4qm9qcw5sc5n1k5jznc83ny02r39-default-builder.sh",
"/nix/store/vj1c3wf9c11a0qs6p3ymfvrnsdgsdcbq-source-stdenv.sh"
],
"name": "mytool",
"outputs": {
"out": {
"path": "/nix/store/blm702jzcwfppwrrj9925ivd9gxp4c9n-mytool"
}
},
"system": "x86_64-linux"
}
}
The path
./examples/flake-simple#packages.x86_64-linux.mytool
is
referred to as a Flake output attribute installable, or simply an installable.
An installable is a Flake output that can be realized in the Nix store.
./examples/flake-simple
refers to this
repository’s flake.nix
directory.packages.x86_64-linux.mytool
following
#
is an output attribute defined within the flake.Most modern Nix commands accept
installables as input, making them a fundamental
concept in working with Flakes. You should only use the modern
commands, e.g. nix <subcommand>
. Stay away
from the command nix-env
.