status
this chapter is in active development
expect live edits and rapid iteration (except for when i am really busy with other stuff) while this material is written.
primitives
strings, numbers, paths, booleans, lists, and null.
status
this chapter is in active development
expect live edits and rapid iteration (except for when i am really busy with other stuff) while this material is written.
strings, numbers, paths, booleans, lists, and null.
nine types. seven primitives, plus attribute sets and functions (which get their own pages).
"hello"double-quoted or multi-line with ''4264-bit signed. overflow is a hard error3.1464-bit. rare in practicetruetrue or false. lowercasenulla distinct type, separate from false and 0./srcresolves relative to the file, not the shell[ 1 2 3 ]ordered, heterogeneous. spaces, no commas{ a = 1; }next pagex: x + 1two pages outfire up nix repl and follow along.
"hello" + " " + "world"
# "hello world"
interpolation with ${}:
let name = "curl"; in "package: ${name}"
# "package: curl"
the expression inside ${} must evaluate to a string. nix does not silently coerce integers. "count: ${42}" is an error. use toString:
let n = 42; in "count: ${toString n}"
# "count: 42"
two single quotes ('') delimit multi-line strings. nix strips common leading whitespace:
''
first line
second line
''
# "first line\nsecond line\n"
this matters when you embed shell scripts in derivations:
buildPhase = ''
mkdir -p $out/bin
gcc -o $out/bin/hello hello.c
'';
the two spaces before mkdir are relative to the delimiters. they get stripped.
1 + 2 # 3
7 / 2 # 3
integer division truncates.
floats exist (1.0 + 2.5 gives 3.5) but are rare. you will almost never write one.
true && false # false
!true # false
if true then "yes" else "no"
# "yes"
if is an expression. it returns a value. the else branch is required.
null == null # true
null == false # false
its own type. no implicit conversions.
paths are not strings.
./src
# /home/karol/project/src
./.
# /home/karol/project
relative paths resolve against the directory of the nix file that contains them. not the working directory of your shell. ./src in a default.nix always points to the src next to that file, regardless of where you run nix-build.
interpolate a path into a string and nix copies it into the store:
"${./hello.c}"
# "/nix/store/...-hello.c"
that is how source files enter the build system.
import <nixpkgs>
<nixpkgs> is a lookup against NIX_PATH. it resolves to wherever your system has nixpkgs. flakes replace this, but you will see it in older code.
ordered, heterogeneous, space-separated. no commas.
[ 1 2 3 ]
[ "hello" 42 true null ]
[ 1 2 ] ++ [ 3 4 ]
# [ 1 2 3 4 ]
++ concatenates. no index operator. builtins.elemAt does it:
builtins.elemAt [ "a" "b" "c" ] 1
# "b"
lists show up in buildInputs, propagatedBuildInputs, meta.platforms. you rarely need to index into them.
builtins.typeOf "hello" # "string"
builtins.typeOf 42 # "int"
builtins.typeOf ./src # "path"
builtins.typeOf { a = 1; } # "set"
builtins.typeOf (x: x) # "lambda"
attribute sets are "set". functions are "lambda". these show up in error messages.
attribute sets is the data structure everything in nix revolves around: nesting, merging, recursive sets, let...in, with, and inherit.