The official documentation about the operators in nix can be found here

🚧🚧🚧 This site is WIP

Official List

Attribute selectionAttrSet . AttrPath [ or expr ]none1
Function applicationfunc exprleft2
Arithmetic negation- numbernone3
Has attributeAttrSet ? AttrPathnone4
ist concatenationlist ++ listright5
Multiplicationnumber * numberleft6
Divisionnumber / numberleft6
Subtractionnumber - numberleft7
Additionnumber + numberleft7
String concatenationstring + stringleft7
Path concatenationpath + pathleft7
Path and string concatenationpath + stringleft7
String and path concatenationstring + pathleft7
Logical negation (NOT)! boolnone8
UpdateAttrSet // AttrSetright9
Less thanexpr < exprnone10
Less than or equal toexpr <= exprnone10
Greater thanexpr > exprnone10
Greater than or equal toexpr >= exprnone10
Equalityexpr == exprnone11
Inequalityexpr != exprnone11
Logical conjunction (AND)bool && boolleft12
Logical disjunction (OR)bool \|\| boolleft13
Logical implicationbool -> boolnone14

Type signatures

From a type perspective those operators can be seen as lambda functions. Every operator takes (one or more) arguments of a type and returns a type. The following list was created to clarify the type signatures.

Some operators take one or two arguments, they can either take them from left or right hand side.

Some formals

for simplicity this document follows these conventions:

  • R is used as Right hand side type.
  • L is used as Left hand side type.
  • When using the proposed lambda notation, the first argument is always LHS and the second the RHS of the discussed operator.
  • T,U,W are used as generic Type variables mostly do denote the resulting type, or types of free variables.
  • a,b,... can be of any type. They are type variables.
  • x is a functions input value
  • y is a functions return value
  • f, g, h are used to give names to functions.

'.' - Attribute selection

Usage of the (.) operator:

L must be an AttrSet, and R must be of type String

 L(.)R = L.R

Since attribute sets are defined as lists of pairs. The . operation simply finds the matching first pair and returns the second pair (which is the value). If the value doesn't exist it raises an Error in the value world which means it returns type Never in the type world.

 L(.)R = L -> R -> T
 L(.)R :: { ${name} :: a } -> String -> a | Never

If R itself contains an expression this must be parenthesized with the ( ) operator. This operator tells us to evaluate the expression in R before passing it to the (.) operator.


 { "car" :: String; "bus" :: Int }.("car" | "bus")
 # Evaluates to
 String | Int

Attribute selection in conjunction with or

The or operator simply narrows out the Never type and instead returns a fallback value with the type of b.

 L.R (`or`) b = L.R or b
 L.R (`or`) b :: { ${name} :: a } -> String -> a | b

Function application

Let f be a function; x its applied argument and y the applied function result.

 y = f x

For comprehensiveness let the type signature of the above function be L and the applied argument R.

blow the argument R is applied to a function of type L.

 L R = L -> R -> T
 L R :: (a -> b) -> a -> b

'-' - minus operator

(Number -> Number -> Number)

'+' - plus operator

Larg :: String | Path;
Rarg  :: String | Path;
(Larg -> Rarg -> Larg) | (Number -> Number -> Number)

'?' - Has attribute

'++' - List concatenation

'<' '>' - comparison

'==' - Equality

'!=' - Inequality

'*' - Multiplication

'!' - Negation

'//' - Update

'&&' '||' '->' - Logical