{"id":13625174,"url":"https://github.com/tazjin/nix-1p","last_synced_at":"2025-05-16T17:04:08.351Z","repository":{"id":46106465,"uuid":"200123415","full_name":"tazjin/nix-1p","owner":"tazjin","description":"A (more or less) one page introduction to Nix, the language.","archived":false,"fork":false,"pushed_at":"2024-04-16T17:20:17.000Z","size":26,"stargazers_count":951,"open_issues_count":7,"forks_count":24,"subscribers_count":18,"default_branch":"master","last_synced_at":"2025-05-15T02:57:11.704Z","etag":null,"topics":["functional-programming","hacktoberfest","nix","nixos","nixpkgs","purity"],"latest_commit_sha":null,"homepage":"https://code.tvl.fyi/about/nix/nix-1p","language":"Nix","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tazjin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-08-01T21:49:02.000Z","updated_at":"2025-05-12T04:19:30.000Z","dependencies_parsed_at":"2024-01-13T17:11:43.405Z","dependency_job_id":"3465eb8f-fba5-4fa7-87c1-b613bf0cec93","html_url":"https://github.com/tazjin/nix-1p","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tazjin%2Fnix-1p","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tazjin%2Fnix-1p/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tazjin%2Fnix-1p/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tazjin%2Fnix-1p/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tazjin","download_url":"https://codeload.github.com/tazjin/nix-1p/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254573589,"owners_count":22093731,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["functional-programming","hacktoberfest","nix","nixos","nixpkgs","purity"],"created_at":"2024-08-01T21:01:51.673Z","updated_at":"2025-05-16T17:04:08.295Z","avatar_url":"https://github.com/tazjin.png","language":"Nix","funding_links":[],"categories":["Nix","Learning"],"sub_categories":[],"readme":"\u003e [!TIP]\n\u003e Are you interested in hacking on Nix projects for a week, together\n\u003e with other Nix users? Do you have time at the end of August? Great,\n\u003e come join us at [Volga Sprint](https://volgasprint.org/)!\n\nNix - A One Pager\n=================\n\n[Nix](https://nixos.org/nix/), the package manager, is built on and with Nix,\nthe language. This page serves as a fast intro to most of the (small) language.\n\nUnless otherwise specified, the word \"Nix\" refers only to the language below.\n\nPlease file an issue if something in here confuses you or you think something\nimportant is missing.\n\nIf you have Nix installed, you can try the examples below by running `nix repl`\nand entering code snippets there.\n\n\u003c!-- markdown-toc start - Don't edit this section. Run M-x markdown-toc-refresh-toc --\u003e\n**Table of Contents**\n\n- [Overview](#overview)\n- [Language constructs](#language-constructs)\n    - [Primitives / literals](#primitives--literals)\n    - [Operators](#operators)\n        - [`//` (merge) operator](#-merge-operator)\n    - [Variable bindings](#variable-bindings)\n    - [Functions](#functions)\n        - [Multiple arguments (currying)](#multiple-arguments-currying)\n        - [Multiple arguments (attribute sets)](#multiple-arguments-attribute-sets)\n    - [`if ... then ... else ...`](#if--then--else-)\n    - [`inherit` keyword](#inherit-keyword)\n    - [`with` statements](#with-statements)\n    - [`import` / `NIX_PATH` / `\u003centry\u003e`](#import--nix_path--entry)\n    - [`or` expressions](#or-expressions)\n- [Standard libraries](#standard-libraries)\n    - [`builtins`](#builtins)\n    - [`pkgs.lib`](#pkgslib)\n    - [`pkgs` itself](#pkgs-itself)\n- [Derivations](#derivations)\n- [Nix Idioms](#nix-idioms)\n    - [File lambdas](#file-lambdas)\n    - [`callPackage`](#callpackage)\n    - [Overrides / Overlays](#overrides--overlays)\n\n\u003c!-- markdown-toc end --\u003e\n\n\n# Overview\n\nNix is:\n\n*   **purely functional**. It has no concept of sequential steps being executed,\n    any dependency between operations is established by depending on *data* from\n    previous operations.\n\n    Any valid piece of Nix code is an *expression* that returns a value.\n\n    Evaluating a Nix expression *yields a single data structure*, it does not\n    execute a sequence of operations.\n\n    Every Nix file evaluates to a *single expression*.\n*   **lazy**. It will only evaluate expressions when their result is actually\n    requested.\n\n    For example, the builtin function `throw` causes evaluation to stop.\n    Entering the following expression works fine however, because we never\n    actually ask for the part of the structure that causes the `throw`.\n\n    ```nix\n    let attrs = { a = 15; b = builtins.throw \"Oh no!\"; };\n    in \"The value of 'a' is ${toString attrs.a}\"\n    ```\n*   **purpose-built**. Nix only exists to be the language for Nix, the package\n    manager. While people have occasionally used it for other use-cases, it is\n    explicitly not a general-purpose language.\n\n# Language constructs\n\nThis section describes the language constructs in Nix. It is a small language\nand most of these should be self-explanatory.\n\n## Primitives / literals\n\nNix has a handful of data types which can be represented literally in source\ncode, similar to many other languages.\n\n```nix\n# numbers\n42\n1.72394\n\n# strings \u0026 paths\n\"hello\"\n./some-file.json\n\n# strings support interpolation\n\"Hello ${name}\"\n\n# multi-line strings (common prefix whitespace is dropped)\n''\nfirst line\nsecond line\n''\n\n# lists (note: no commas!)\n[ 1 2 3 ]\n\n# attribute sets (field access with dot syntax)\n{ a = 15; b = \"something else\"; }\n\n# recursive attribute sets (fields can reference each other)\nrec { a = 15; b = a * 2; }\n```\n\n## Operators\n\nNix has several operators, most of which are unsurprising:\n\n| Syntax                    | Description                                                                 |\n|---------------------------|-----------------------------------------------------------------------------|\n| `+`, `-`, `*`, `/`        | Numerical operations                                                        |\n| `+`                       | String concatenation                                                        |\n| `++`                      | List concatenation                                                          |\n| `==`                      | Equality                                                                    |\n| `\u003e`, `\u003e=`, `\u003c`, `\u003c=`      | Ordering comparators                                                        |\n| `\u0026\u0026`                      | Logical `AND`                                                               |\n| \u003ccode\u003e\u0026vert;\u0026vert;\u003c/code\u003e | Logical `OR`                                                                |\n| `e1 -\u003e e2`                | Logical implication (i.e. \u003ccode\u003e!e1 \u0026vert;\u0026vert; e2\u003c/code\u003e)                 |\n| `!`                       | Boolean negation                                                            |\n| `set.attr`                | Access attribute `attr` in attribute set `set`                              |\n| `set ? attribute`         | Test whether attribute set contains an attribute                            |\n| `left // right`           | Merge `left` \u0026 `right` attribute sets, with the right set taking precedence |\n\n\n### `//` (merge) operator\n\nThe `//`-operator is used pervasively in Nix code. You should familiarise\nyourself with it, as it is likely also the least familiar one.\n\nIt merges the left and right attribute sets given to it:\n\n```nix\n{ a = 1; } // { b = 2; }\n\n# yields { a = 1; b = 2; }\n```\n\nValues from the right side take precedence:\n\n```nix\n{ a = \"left\"; } // { a = \"right\"; }\n\n# yields { a = \"right\"; }\n```\n\nThe merge operator does *not* recursively merge attribute sets;\n\n```nix\n{ a = { b = 1; }; } // { a = { c = 2; }; }\n\n# yields { a = { c = 2; }; }\n```\n\nHelper functions for recursive merging exist in the [`lib` library](#pkgslib).\n\n## Variable bindings\n\nBindings in Nix are introduced locally via `let` expressions, which make some\nvariables available within a given scope.\n\nFor example:\n\n```nix\nlet\n  a = 15;\n  b = 2;\nin a * b\n\n# yields 30\n```\n\nVariables are immutable. This means that after defining what `a` or `b` are, you\ncan not *modify* their value in the scope in which they are available.\n\nYou can nest `let`-expressions to shadow variables.\n\nVariables are *not* available outside of the scope of the `let` expression.\nThere are no global variables.\n\n## Functions\n\nAll functions in Nix are anonymous lambdas. This means that they are treated\njust like data. Giving them names is accomplished by assigning them to\nvariables, or setting them as values in an attribute set (more on that below).\n\n```\n# simple function\n# declaration is simply the argument followed by a colon\nname: \"Hello ${name}\"\n```\n\n### Multiple arguments (currying)\n\nTechnically any Nix function can only accept **one argument**. Sometimes\nhowever, a function needs multiple arguments. This is achieved in Nix via\n[currying][], which means to create a function with one argument, that returns a\nfunction with another argument, that returns ... and so on.\n\nFor example:\n\n```nix\nname: age: \"${name} is ${toString age} years old\"\n```\n\nAn additional benefit of this approach is that you can pass one parameter to a\ncurried function, and receive back a function that you can re-use (similar to\npartial application):\n\n```nix\nlet\n  multiply = a: b: a * b;\n  doubleIt = multiply 2; # at this point we have passed in the value for 'a' and\n                         # receive back another function that still expects 'b'\nin\n  doubleIt 15\n\n# yields 30\n```\n\n### Multiple arguments (attribute sets)\n\nAnother way of specifying multiple arguments to a function in Nix is to make it\naccept an attribute set, which enables multiple other features:\n\n```nix\n{ name, age }: \"${name} is ${toString age} years old\"\n```\n\nUsing this method, we gain the ability to specify default arguments (so that\ncallers can omit them):\n\n```nix\n{ name, age ? 42 }: \"${name} is ${toString age} years old\"\n\n```\n\nOr in practice:\n\n```nix\nlet greeter =  { name, age ? 42 }: \"${name} is ${toString age} years old\";\nin greeter { name = \"Slartibartfast\"; }\n\n# yields \"Slartibartfast is 42 years old\"\n# (note: Slartibartfast is actually /significantly/ older)\n```\n\nAdditionally we can introduce an ellipsis using `...`, meaning that we can\naccept an attribute set as our input that contains more variables than are\nneeded for the function.\n\n```nix\nlet greeter = { name, age, ... }: \"${name} is ${toString age} years old\";\n    person = {\n      name = \"Slartibartfast\";\n      age = 42;\n      # the 'email' attribute is not expected by the 'greeter' function ...\n      email = \"slartibartfast@magrath.ea\";\n    };\nin greeter person # ... but the call works due to the ellipsis.\n```\n\nNix also supports binding the whole set of passed in attributes to a\nparameter using the `@` syntax:\n\n```nix\nlet func = { name, age, ... }@args: builtins.attrNames args;\nin func {\n    name = \"Slartibartfast\";\n    age = 42;\n    email = \"slartibartfast@magrath.ea\";\n}\n\n# yields: [ \"age\" \"email\" \"name\" ]\n```\n\n**Warning:** Combining the `@` syntax with default arguments can lead\nto surprising behaviour, as the passed attributes are bound verbatim.\nThis means that defaulted arguments are not included in the bound\nattribute set:\n\n```nix\n({ a ? 1, b }@args: args.a) { b = 1; }\n# throws: error: attribute 'a' missing\n\n({ a ? 1, b }@args: args.a) { b = 1; a = 2; }\n# =\u003e 2\n```\n\n## `if ... then ... else ...`\n\nNix has simple conditional support. Note that `if` is an **expression** in Nix,\nwhich means that both branches must be specified.\n\n```nix\nif someCondition\nthen \"it was true\"\nelse \"it was false\"\n```\n\n## `inherit` keyword\n\nThe `inherit` keyword is used in attribute sets or `let` bindings to \"inherit\"\nvariables from the parent scope.\n\nIn short, a statement like `inherit foo;` expands to `foo = foo;`.\n\nConsider this example:\n\n```nix\nlet\n  name = \"Slartibartfast\";\n  # ... other variables\nin {\n  name = name; # set the attribute set key 'name' to the value of the 'name' var\n  # ... other attributes\n}\n```\n\nThe `name = name;` line can be replaced with `inherit name;`:\n\n```nix\nlet\n  name = \"Slartibartfast\";\n  # ... other variables\nin {\n  inherit name;\n  # ... other attributes\n}\n```\n\nThis is often convenient, especially because inherit supports multiple variables\nat the same time as well as \"inheritance\" from other attribute sets:\n\n```nix\n{\n  inherit name age; # equivalent to `name = name; age = age;`\n  inherit (otherAttrs) email; # equivalent to `email = otherAttrs.email`;\n}\n```\n\n## `with` statements\n\nThe `with` statement \"imports\" all attributes from an attribute set into\nvariables of the same name:\n\n```nix\nlet attrs = { a = 15; b = 2; };\nin with attrs; a + b # 'a' and 'b' become variables in the scope following 'with'\n```\n\nThe scope of a `with`-\"block\" is the expression immediately following the\nsemicolon, i.e.:\n\n```nix\nlet attrs = { /* some attributes */ };\nin with attrs; (/* this is the scope of the `with` */)\n```\n\n## `import` / `NIX_PATH` / `\u003centry\u003e`\n\nNix files can import each other by using the builtin `import` function and a\nliteral path:\n\n```nix\n# assuming there is a file lib.nix with some useful functions\nlet myLib = import ./lib.nix;\nin myLib.usefulFunction 42\n```\n\nThe `import` function will read and evaluate the file, and return its Nix value.\n\nNix files often begin with a function header to pass parameters into the rest of\nthe file, so you will often see imports of the form `import ./some-file { ... }`.\n\nNix has a concept of a `NIX_PATH` (similar to the standard `PATH` environment\nvariable) which contains named aliases for file paths containing Nix\nexpressions.\n\nIn a standard Nix installation, several [channels][] will be present (for\nexample `nixpkgs` or `nixos-unstable`) on the `NIX_PATH`.\n\n`NIX_PATH` entries can be accessed using the `\u003centry\u003e` syntax, which simply\nevaluates to their file path:\n\n```nix\n\u003cnixpkgs\u003e\n# might yield something like `/home/tazjin/.nix-defexpr/channels/nixpkgs`\n```\n\nThis is commonly used to import from channels:\n\n```nix\nlet pkgs = import \u003cnixpkgs\u003e {};\nin pkgs.something\n```\n\n## `or` expressions\n\nNix has a keyword called `or` which can be used to access a value from an\nattribute set while providing a fallback to a default value.\n\nThe syntax is simple:\n\n```nix\n# Access an existing attribute\nlet set = { a = 42; };\nin set.a or 23\n```\n\nSince the attribute `a` exists, this will return `42`.\n\n\n```nix\n# ... or fall back to a default if there is no such key\nlet set = { };\nin set.a or 23\n```\n\nSince the attribute `a` does not exist, this will fall back to returning the\ndefault value `23`.\n\nNote that `or` expressions also work for nested attribute set access.\n\n# Standard libraries\n\nYes, libraries, plural.\n\nNix has three major things that could be considered its standard library and\nwhile there's a lot of debate to be had about this point, you still need to know\nall three.\n\n## `builtins`\n\nNix comes with several functions that are baked into the language. These work\nregardless of which other Nix code you may or may not have imported.\n\nMost of these functions are implemented in the Nix interpreter itself, which\nmeans that they are rather fast when compared to some of the equivalents which\nare implemented in Nix itself.\n\nThe Nix manual has [a section listing all `builtins`][builtins] and their usage.\n\nExamples of builtins that you will commonly encounter include, but are not\nlimited to:\n\n* `derivation` (see [Derivations](#derivations))\n* `toJSON` / `fromJSON`\n* `toString`\n* `toPath` / `fromPath`\n\nThe builtins also include several functions that have the (spooky) ability to\nbreak Nix' evaluation purity. No functions written in Nix itself can do this.\n\nExamples of those include:\n\n* `fetchGit` which can fetch a git-repository using the environment's default\n  git/ssh configuration\n* `fetchTarball` which can fetch \u0026 extract archives without having to specify\n  hashes\n\nRead through the manual linked above to get the full overview.\n\n## `pkgs.lib`\n\nThe Nix package set, commonly referred to by Nixers simply as [nixpkgs][],\ncontains a child attribute set called `lib` which provides a large number of\nuseful functions.\n\nThe canonical definition of these functions is [their source code][lib-src]. I\nwrote a tool ([nixdoc][]) in 2018 which generates manual entries for these\nfunctions, however not all of the files are included as of July 2019.\n\nSee the [Nixpkgs manual entry on `lib`][lib-manual] for the documentation.\n\nThese functions include various utilities for dealing with the data types in Nix\n(lists, attribute sets, strings etc.) and it is useful to at least skim through\nthem to familiarise yourself with what is available.\n\n```nix\n{ pkgs ? import \u003cnixpkgs\u003e {} }:\n\nwith pkgs.lib; # bring contents pkgs.lib into scope\n\nstrings.toUpper \"hello\"\n\n# yields \"HELLO\"\n```\n\n## `pkgs` itself\n\nThe Nix package set itself does not just contain packages, but also many useful\nfunctions which you might run into while creating new Nix packages.\n\nOne particular subset of these that stands out are the [trivial builders][],\nwhich provide utilities for writing text files or shell scripts, running shell\ncommands and capturing their output and so on.\n\n```nix\n{ pkgs ? import \u003cnixpkgs\u003e {} }:\n\npkgs.writeText \"hello.txt\" \"Hello dear reader!\"\n\n# yields a derivation which creates a text file with the above content\n```\n\n# Derivations\n\nWhen a Nix expression is evaluated it may yield one or more *derivations*.\nDerivations describe a single build action that, when run, places one or more\noutputs (whether they be files or folders) in the Nix store.\n\nThe builtin function `derivation` is responsible for creating derivations at a\nlower level. Usually when Nix users create derivations they will use the\nhigher-level functions such as [stdenv.mkDerivation][smkd].\n\nPlease see the manual [on derivations][drv-manual] for more information, as the\ngeneral build logic is out of scope for this document.\n\n# Nix Idioms\n\nThere are several idioms in Nix which are not technically part of the language\nspecification, but will commonly be encountered in the wild.\n\nThis section is an (incomplete) list of them.\n\n## File lambdas\n\nIt is customary to start every file with a function header that receives the\nfiles dependencies, instead of importing them directly in the file.\n\nSticking to this pattern lets users of your code easily change out, for example,\nthe specific version of `nixpkgs` that is used.\n\nA common file header pattern would look like this:\n\n```nix\n{ pkgs ? import \u003cnixpkgs\u003e {} }:\n\n# ... 'pkgs' is then used in the code\n```\n\nIn some sense, you might consider the function header of a file to be its \"API\".\n\n## `callPackage`\n\nBuilding on the previous pattern, there is a custom in nixpkgs of specifying the\ndependencies of your file explicitly instead of accepting the entire package\nset.\n\nFor example, a file containing build instructions for a tool that needs the\nstandard build environment and `libsvg` might start like this:\n\n```nix\n# my-funky-program.nix\n{ stdenv, libsvg }:\n\nstdenv.mkDerivation { ... }\n```\n\nAny time a file follows this header pattern it is probably meant to be imported\nusing a special function called `callPackage` which is part of the top-level\npackage set (as well as certain subsets, such as `haskellPackages`).\n\n```nix\n{ pkgs ? import \u003cnixpkgs\u003e {} }:\n\nlet my-funky-program = pkgs.callPackage ./my-funky-program.nix {};\nin # ... something happens with my-funky-program\n```\n\nThe `callPackage` function looks at the expected arguments (via\n`builtins.functionArgs`) and passes the appropriate keys from the set in which\nit is defined as the values for each corresponding argument.\n\n## Overrides / Overlays\n\nOne of the most powerful features of Nix is that the representation of all build\ninstructions as data means that they can easily be *overridden* to get a\ndifferent result.\n\nFor example, assuming there is a package `someProgram` which is built without\nour favourite configuration flag (`--mimic-threaten-tag`) we might override it\nlike this:\n\n```nix\nsomeProgram.overrideAttrs(old: {\n    configureFlags = old.configureFlags or [] ++ [\"--mimic-threaten-tag\"];\n})\n```\n\nThis pattern has a variety of applications of varying complexity. The top-level\npackage set itself can have an `overlays` argument passed to it which may add\nnew packages to the imported set.\n\nNote the use of the `or` operator to default to an empty list if the\noriginal flags do not include `configureFlags`. This is required in\ncase a package does not set any flags by itself.\n\nSince this can change in a package over time, it is useful to guard\nagainst it using `or`.\n\nFor a slightly more advanced example, assume that we want to import `\u003cnixpkgs\u003e`\nbut have the modification above be reflected in the imported package set:\n\n```nix\nlet\n  overlay = (final: prev: {\n    someProgram = prev.someProgram.overrideAttrs(old: {\n      configureFlags = old.configureFlags or [] ++ [\"--mimic-threaten-tag\"];\n    });\n  });\nin import \u003cnixpkgs\u003e { overlays = [ overlay ]; }\n```\n\nThe overlay function receives two arguments, `final` and `prev`. `final` is\nthe [fixed point][fp] of the overlay's evaluation, i.e. the package set\n*including* the new packages and `prev` is the \"original\" package set.\n\nSee the Nix manual sections [on overrides][] and [on overlays][] for more\ndetails (note: the convention has moved away from using `self` in favor of\n`final`, and `prev` instead of `super`, but the documentation has not been\nupdated to reflect this).\n\n[currying]: https://en.wikipedia.org/wiki/Currying\n[builtins]: https://nixos.org/manual/nix/stable/language/builtins\n[nixpkgs]: https://github.com/NixOS/nixpkgs\n[lib-src]: https://github.com/NixOS/nixpkgs/tree/master/lib\n[nixdoc]: https://github.com/tazjin/nixdoc\n[lib-manual]: https://nixos.org/manual/nixpkgs/stable/#sec-functions-library\n[channels]: https://nixos.org/manual/nix/stable/command-ref/files/channels\n[trivial builders]: https://github.com/NixOS/nixpkgs/blob/master/pkgs/build-support/trivial-builders/default.nix\n[smkd]: https://nixos.org/manual/nixpkgs/stable/#chap-stdenv\n[drv-manual]: https://nixos.org/manual/nix/stable/language/derivations\n[fp]: https://github.com/NixOS/nixpkgs/blob/master/lib/fixed-points.nix\n[on overrides]: https://nixos.org/manual/nixpkgs/stable/#chap-overrides\n[on overlays]: https://nixos.org/manual/nixpkgs/stable/#chap-overlays\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftazjin%2Fnix-1p","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftazjin%2Fnix-1p","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftazjin%2Fnix-1p/lists"}