Language
Updated: August 4, 2026
Nix functional programming language. Key take aways.
Evaluation –> Nix expressions yield one data structure
Lazy Evaluation –> Will only evaluate results that are requested
Purely Functional –> No sequence of operations, any order is fine
Type Inference –> Nix figures out types, do not have to list types
Type Checking –> Nix checks types
Declarative –> List requirements for the build, and nix builds them
Immutable –> Cannot change state, only build a new one.
Derivation –> A build task
Impermanance –> Deletes a significant of unneeded data from the system during boot
Nix is not a general purpose language. It is a domain specific language.
DSLs are geared for a specific purpose. For nix, that is building programs and systems.
Nix Language (key)
Nix does not care about newlines or indentation.
Anything placed inside a .nix is called an expression (unevaluated)
. key syntax returns values from the expression (evaluated) nixpkgs has an attribute set called lib which has largest amount of useful functions.
[ ] # an empty list, separate with spaces, not commas, "quote strings"
{ } # an empty set, separate with commas
{ x, y, }: # attribute set argument || destructuring. These are attribute requirements
{ ... } # ellipsis means accept arguments that contain additional attributes
'' ''; # indented strings || multi-line strings
<nixpkgs> # angle bracket syntax lookup paths
; # statement separator or function call
${ var } # variable using string ${interpolation} ensures nix uses the value
? # whatever follows is the default option (right side of default argument)
+ # string concatenation
++ # list concatenation
@ # provides an attribute to refer to a set of values
-> # logical implication, False if e1 is true and e2 is false
// # update: merge attrset with preference on right will override or extend attrset // attrset
./. # relative path for current folder
relative/path # relative path
/absolute/path # absolute paths always start with /
rec { ... } # recursive: access attributes within the set
argument:body # function, : , has 2 parts, argument and body
myfunc = a: a + 1 # single function
x: y: x + y # curried function. Equivalent to x: (y: x = y). Takes an arg and return func y: x + y with x set to the value
#### set of attributes with defaults in it.
{ pkgs ? import <nixpkgs> {}, lib ? pkgs.lib, ... }: # the ellipsis ... means the rest of the attributes are ignored
let ... in # define local variables for use in an expression known as a let binding
with e1; e2 # adds lexical scope of e1 set into e2
rec # add to lexical scope, like when a var needs the value of another var
import # import another file, func, expression !! folders need a default.nix
self # attribute that refers to itself, ie things in the file that are not sourced from an input
inherit # inherit system is same as system = system
if then # if conditions require else. must be if then else.
Builtins
primative operations (primops) are builtin functions builtins
- abort
- baseNameOf
- break
- derivation
- derivationStrict
- dirOf
- false
- fetchGit
- fetchMercurial
- fetchTarball
- fetchTree
- fromTOML
- import
- isNull
- null
- map
- placeholder
- removeAttrs
- scopedImport
- throw
- toString
- true
Functions
# lets see how it pieces together
let
myfunc = { a, b }: a + b;
in
myfunc { a = 1; b = 2; } # curried to evaluated functions to produce final output 3 (result)
# what is looks like in a nix expression
{ config, pkgs, ... }: # curried function
Assert
# check for requirements, if true, perform, otherwise fail and print backtrace
{ localServer ? false
, httpServer ? false
, openssl ? null }:
# each
assert localServer -> db4 != null; ①
assert httpServer -> httpd != null && httpd.expat == expat; ②
assert sslSupport -> openssl != null && (httpServer -> httpd.openssl == openssl); ③