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

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); ③