Nix Tutorial 2 : Data Types & Language Constructs - wimsio/universities GitHub Wiki
This guide introduces the types of data in Nix and the main language features, with simple explanations, icons, and real examples for newcomers.
Every value in Nix has a type. Knowing these types helps you write correct and maintainable Nix expressions.
-
Description: Signed 64-bit numbers, e.g.,
123
,-42
-
Example:
let a = 5; b = -3; in a + b # Result: 2
-
Check type:
builtins.isInt a
โtrue
-
Description: 64-bit floating-point numbers, e.g.,
1.5
,-0.02
,.1e5
-
Example:
let pi = 3.1415; in pi * 2 # Result: 6.283
-
Check type:
builtins.isFloat pi
โtrue
-
Description: Only two values:
true
orfalse
-
Example:
let flag = true; in if flag then "Yes" else "No" # Result: "Yes"
-
Check type:
builtins.isBool flag
โtrue
-
Description: Immutable sequence of bytes (not characters!); written with double quotes
"foo"
or indented strings''foo''
-
Example:
let msg = "Hello, Nix!"; in msg
let multi = '' Line 1 Line 2 ''; in multi
-
Check type:
builtins.isString msg
โtrue
-
Description: POSIX-style file paths (e.g.,
./file.txt
,/etc/hosts
). Paths and strings are not the same. -
Example:
let f = ./file.txt; # relative path g = /etc/hosts; # absolute path in f
-
Check type:
builtins.isPath f
โtrue
Note:
Paths are resolved relative to their base directory.
"./foo.txt"
(as a string) is different from ./foo.txt
(as a path).
-
Description: The single value
null
(like "nothing" or "None" in other languages) -
Example:
let val = null; in if val == null then "empty" else "not empty"
-
Check type:
val == null
โtrue
-
Description: Key-value pairs, like dictionaries or objects in other languages.
-
Example:
let person = { name = "Alice"; age = 30; }; in person.name # Result: "Alice"
-
Check type:
builtins.isAttrs person
โtrue
Access keys: set.key
Nested sets: { a = { b = 2; }; }
โ access with .a.b
-
Description: Ordered collections (arrays) of values, in square brackets.
-
Example:
let xs = [ 1 2 3 ]; in builtins.length xs # Result: 3
-
Check type:
builtins.isList xs
โtrue
Access elements: builtins.elemAt xs 0
โ 1
-
Description: Functions are first-class in Nix. You can pass them around, store them, and call them.
-
Example:
let inc = x: x + 1; in inc 4 # Result: 5
let add = { x, y }: x + y; in add { x = 2; y = 3; } # Result: 5
-
Check type:
builtins.isFunction inc
โtrue
- Description: Opaque values created by plugins. Usually not used in everyday Nix code.
- Example: Not commonly encountered for new users.
-
String context is metadata that tracks where a string came from (for reproducibility).
-
You donโt need to deal with string context directly.
-
Checking context:
builtins.hasContext "hello" # false
builtins.getContext (builtins.storePath "/nix/store/xyz-foo")
-
Clearing context:
builtins.unsafeDiscardStringContext someString
-
Most users never need to touch thisโjust know it exists!
-
String:
"hello"
,''multi-line''
-
Number:
42
,1.2
,-7
-
Path:
./foo.txt
,/etc/passwd
-
List:
[ 1 2 3 ]
-
Attribute set:
{ key = "val"; }
-
Define:
{ a = 1; b = "foo"; }
-
Access:
{ a = 1; } .a # 1
-
Default value:
{ a = 1; } .b or 42 # 42
-
Complex keys:
{ "foo bar" = 123; }."foo bar" # 123
-
Allow self-reference among keys:
rec { x = y; y = 10; }.x # Result: 10
-
Define local variables:
let a = 1; b = 2; in a + b # 3
-
Copy from scope or other set:
let x = 5; in { inherit x; y = 3; } # { x = 5; y = 3; }
let set = { a = 1; b = 2; }; in { inherit (set) a; } # { a = 1; }
-
Anonymous function:
x: x * 2
-
Function with attribute set as argument:
{ a, b }: a + b
-
Default value for function argument:
{ x, y ? 5 }: x + y
( { x, y ? 2 }: x * y ) { x = 3; } # 6
-
If-else:
if true then "yes" else "no"
-
Check conditions, fail early if not met:
assert 1 < 2; "ok" # "ok" assert false; "fail" # Error!
-
Bring all attributes into scope:
let as = { x = 1; y = 2; }; in with as; x + y # 3
-
Single line:
# Comment
-
Multi-line:
/* Block comment */
-
Normal:
"Hello, Nix!"
-
Indented/multi-line:
'' First line Second line ''
- Start with a letter or
_
. - Can contain letters, digits,
_
,'
,-
. - Some words are reserved (like
let
,if
,else
).
-
Insert variables or expressions into strings with
${...}
-
Example:
let name = "world"; in "Hello, ${name}!" # "Hello, world!"
-
In attribute names:
let key = "foo"; in { ${key} = 123; } # { foo = 123; }
Arithmetic: +
, -
, *
, /
Comparison: <
, >
, ==
, !=
, <=
, >=
Logical: &&
, ||
, !
, ->
(implication)
Update sets: //
String concat: +
List concat: ++
Path concat: +
-
Example:
( { a = 1; } // { b = 2; } ) # { a = 1; b = 2; } [ 1 2 ] ++ [ 3 4 ] # [ 1 2 3 4 ]
Type | Example | Check Type |
---|---|---|
Integer | 123 |
builtins.isInt 123 |
Float | 3.14 |
builtins.isFloat 3.14 |
Boolean | true |
builtins.isBool true |
String | "foo" |
builtins.isString "foo" |
Path | ./file.txt |
builtins.isPath ./file.txt |
Null | null |
val == null |
Attribute Set | { a = 1; } |
builtins.isAttrs {} |
List | [ 1 2 3 ] |
builtins.isList [1] |
Function | x: x + 1 |
builtins.isFunction (x: x) |
External | Plugin-defined | N/A |