This commit is contained in:
commit
95a533c876
451 changed files with 18255 additions and 0 deletions
92
docs/introduction-to-nix/derivations.md
Normal file
92
docs/introduction-to-nix/derivations.md
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
# Derivations
|
||||
|
||||
At its core, Nix is about building software. Nix doesn't install software directly from a global repository; instead, it builds *derivations*. A derivation is a description of how to build a package. It's a pure function `inputs -> output`, meaning given the same inputs, it will always produce the same output.
|
||||
|
||||
## Your first Derivation
|
||||
|
||||
Let's build a simple "hello world" program.
|
||||
|
||||
First, create a C source file `hello.c`:
|
||||
|
||||
```c
|
||||
// hello.c
|
||||
#include <stdio.h>
|
||||
|
||||
int main() {
|
||||
printf("Hello from C!\n");
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
Then, create a `default.nix` file that imports Nixpkgs and then calls the package definition below.
|
||||
|
||||
```nix
|
||||
# default.nix
|
||||
{ pkgs ? import <nixpkgs> {} }: # Fetch Nixpkgs
|
||||
# Nixpkgs is a collection of Nix expressions.
|
||||
# We need some functions (like `callPackage`) that are defined there.
|
||||
# Nixpkgs will be covered later in this guide.
|
||||
|
||||
pkgs.callPackage ./my-hello.nix { }
|
||||
# `callPackage` is a helper function for Package derivations.
|
||||
# It automatically resolves all needed input arguments the derivation needs from Nixpkgs.
|
||||
```
|
||||
|
||||
> Hint: `default.nix` will get replaced by Nix Flakes later. You do not need to know what Flakes are at the moment, but keep this relationship in mind.
|
||||
|
||||
Now, define how to build the C source file a Nix file, `my-hello`.nix:
|
||||
|
||||
```nix
|
||||
# my-hello.nix
|
||||
{ stdenv }: # Inputs
|
||||
|
||||
stdenv.mkDerivation {
|
||||
pname = "my-hello"; # Package name
|
||||
version = "0.1.0"; # Package version
|
||||
|
||||
src = ./.; # The source code for the package is in the current directory
|
||||
|
||||
# Phases of the build process
|
||||
# mkDerivation defines standard phases like unpackPhase, patchPhase, configurePhase, buildPhase, installPhase
|
||||
# For simple builds, we just need build and install.
|
||||
|
||||
buildPhase = ''
|
||||
# Compile command
|
||||
${stdenv.cc}/bin/gcc hello.c -o hello
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
# Install the compiled program into the output directory ($out)
|
||||
mkdir -p $out/bin
|
||||
cp hello $out/bin/hello
|
||||
'';
|
||||
}
|
||||
```
|
||||
|
||||
Let's break this down:
|
||||
|
||||
- `stdenv`: This derivation is a function that expects `stdenv` (standard environment, providing common build tools and phases) as an argument. It will be automatically resolved from Nixpkgs.
|
||||
- `stdenv.mkDerivation`: This is the core function to create a derivation. It sets up a standard build environment and provides a set of common build phases.
|
||||
- `pname`, `version`: Standard metadata for the package.
|
||||
- `src = ./.;`: This tells Nix to copy all files from the current directory into the build sandbox.
|
||||
- `buildPhase`: This is where you put commands to compile your software. Here, `gcc` is used from the standard C compiler provided by `stdenv.cc` to compile `hello.c` into an executable `hello`.
|
||||
- `installPhase`: This is where you put commands to install the build artifacts into the `$out` directory, which is the final location in the Nix store. Here, a `bin` directory is created to move the `hello` executable into.
|
||||
|
||||
## Building and Running a Derivation
|
||||
|
||||
To build this derivation, use `nix build`:
|
||||
|
||||
```bash
|
||||
nix build --file default.nix
|
||||
```
|
||||
|
||||
You'll see output from the build process. If successful, Nix creates a `result` symlink in your current directory. This `result` symlink points to the package in the Nix store.
|
||||
|
||||
Now, run your compiled program:
|
||||
|
||||
```bash
|
||||
./result/bin/hello
|
||||
```
|
||||
```
|
||||
Hello from C!
|
||||
```
|
||||
209
docs/introduction-to-nix/flakes.md
Normal file
209
docs/introduction-to-nix/flakes.md
Normal file
|
|
@ -0,0 +1,209 @@
|
|||
# Flakes
|
||||
|
||||
> Flakes are still an experimental feature in Nix. However, they are so widely used by the community that they almost became standard. Furthermore, *synix* uses Flakes.
|
||||
|
||||
Nix flakes are a reproducible way to define, build, and deploy Nix projects, making them reliable and portable.
|
||||
|
||||
Flakes accomplish that by:
|
||||
|
||||
## Standardized Input
|
||||
|
||||
They define a fixed, declarative input (the `flake.nix` file) that specifies all project dependencies, sources, and outputs. This eliminates implicit dependencies or environment variables that could cause builds to differ.
|
||||
|
||||
Example in `flake.nix`:
|
||||
|
||||
```nix
|
||||
inputs = {
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11"; # Declare we need nixpkgs, specifically this branch
|
||||
};
|
||||
```
|
||||
|
||||
## Reproducible "Lock File"
|
||||
|
||||
When you build or develop with a flake, Nix generates a `flake.lock` file. This file records the *exact* content-addressable hashes of *all* transitive inputs used for that specific build. This lock file can be committed to version control, ensuring that anyone else cloning the repository (or a CI system) will use precisely the same set of inputs and thus achieve the identical result.
|
||||
|
||||
Example `flake.lock` entry for `nixpkgs`:
|
||||
|
||||
```json
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1709259160,
|
||||
"narHash": "sha256-...",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "b2f67f0b5d1a8e1b3c9f2d1e0f0e0c0b0a090807", // The exact commit!
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github",
|
||||
"url": "github:NixOS/nixpkgs/nixos-23.11"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Flake Schema
|
||||
|
||||
The `flake.nix` has a well-defined structure for `inputs` (sources like Git repos, other flakes) and `outputs` (packages, applications, modules, etc.). This consistent schema makes flakes composable and predictable.
|
||||
|
||||
A `flake.nix` file typically looks like this:
|
||||
|
||||
```nix
|
||||
# flake.nix
|
||||
{
|
||||
description = "A simple example flake";
|
||||
|
||||
inputs = {
|
||||
# Inputs are other flakes or external resources
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11"; # Locked to a specific branch/version
|
||||
# This is how you would add synix to your flake:
|
||||
# synix.url = "git+https://git.sid.ovh/sid/synix"
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, ... }@inputs: # 'self' refers to this flake, inputs are available
|
||||
let
|
||||
# Define common arguments for packages from nixpkgs
|
||||
# This ensures all packages use the same version of Nixpkgs on this system
|
||||
pkgs = import nixpkgs {
|
||||
system = "x86_64-linux"; # The target system architecture
|
||||
};
|
||||
in
|
||||
{
|
||||
# Outputs include packages, devShells, modules, etc.
|
||||
# Packages that can be built by `nix build .#<package-name>`
|
||||
packages.x86_64-linux.my-app = pkgs.callPackage ./pkgs/my-app { };
|
||||
packages.x86_64-linux.my-other-app = pkgs.hello; # From nixpkgs directly
|
||||
|
||||
# Development shells that can be entered using `nix develop`
|
||||
devShells.x86_64-linux.default = pkgs.mkShell {
|
||||
name = "my-dev-env";
|
||||
buildInputs = [ pkgs.nodejs pkgs.python3 ];
|
||||
shellHook = "echo 'Welcome to my dev environment!'";
|
||||
};
|
||||
|
||||
# NixOS modules (for system config)
|
||||
# nixosConfigurations.<hostname>.modules = [ ./nixos-modules/webserver.nix ];
|
||||
# (This is more advanced and will be covered in NixOS section)
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
Key parts of a `flake.nix`:
|
||||
|
||||
- `description`: A human-readable description of your flake.
|
||||
- `inputs`: Defines all dependencies of your flake. Each input has a `url` pointing to another flake (e.g., a GitHub repository, a local path, or a Git URL) and an optional `follows` attribute to link inputs.
|
||||
- `outputs`: A function that takes `self` (this flake) and all `inputs` as arguments. It returns an attribute set defining what this flake provides. Common outputs are `packages`, `devShells`, `nixosConfigurations`, etc., usually segregated by system architecture. You can read more about flake outputs in the [NixOS & Flakes Book](https://nixos-and-flakes.thiscute.world/other-usage-of-flakes/outputs).
|
||||
|
||||
## `nix flake` Commands
|
||||
|
||||
The `nix flake` subcommand is your primary interface for interacting with flakes. Let's create a new flake to demonstrate them:
|
||||
|
||||
Initialize the flake:
|
||||
|
||||
```bash
|
||||
mkdir my-flake && cd my-flake
|
||||
nix flake init
|
||||
```
|
||||
|
||||
This creates a minimal `flake.nix`.
|
||||
|
||||
Lock your flake:
|
||||
|
||||
```bash
|
||||
nix flake lock
|
||||
```
|
||||
|
||||
This creates `flake.lock`, a file that locks the exact versions of your inputs.
|
||||
|
||||
Update flake inputs:
|
||||
|
||||
```bash
|
||||
nix flake update
|
||||
```
|
||||
|
||||
This updates all inputs to their latest versions allowed by their `url` (e.g., the latest commit on `nixos-unstable` for `nixpkgs`) and then updates the `flake.lock` file. Since we just locked the flake for the first time, there probably won't be any updates available.
|
||||
|
||||
Print flake inputs:
|
||||
|
||||
```bash
|
||||
nix flake metadata
|
||||
```
|
||||
|
||||
Print flake outputs:
|
||||
|
||||
```bash
|
||||
nix flake show
|
||||
```
|
||||
|
||||
Build packages from a flake:
|
||||
|
||||
```bash
|
||||
nix build .#hello # The '.' refers to the current directory's flake
|
||||
./result/bin/hello
|
||||
```
|
||||
|
||||
Run a package from a flake:
|
||||
|
||||
```bash
|
||||
nix run .#hello
|
||||
```
|
||||
|
||||
Since the `packages.<system>.default` output exists, you can just do `nix run`.
|
||||
|
||||
## `nix develop`
|
||||
|
||||
This command spins up a temporary shell environment with all the tools and dependencies specified in your flake's `devShells` output.
|
||||
|
||||
Let's expand your `flake.nix`:
|
||||
|
||||
```nix
|
||||
# flake.nix
|
||||
{
|
||||
description = "A very basic flake";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
|
||||
};
|
||||
|
||||
outputs =
|
||||
{ self, nixpkgs }:
|
||||
let
|
||||
# Define `pkgs` for the current system
|
||||
pkgs = import nixpkgs {
|
||||
system = "x86_64-linux";
|
||||
};
|
||||
in
|
||||
{
|
||||
packages.x86_64-linux.hello = nixpkgs.legacyPackages.x86_64-linux.hello;
|
||||
# With `pkgs` defined, we could also do this:
|
||||
# packages.x86_64-linux.hello = pkgs.hello;
|
||||
|
||||
packages.x86_64-linux.default = self.packages.x86_64-linux.hello;
|
||||
|
||||
devShells.x86_64-linux.default = pkgs.mkShell {
|
||||
# Packages available in the shell
|
||||
packages = [
|
||||
pkgs.git
|
||||
pkgs.go
|
||||
pkgs.neovim
|
||||
];
|
||||
# Environment variables for the shell
|
||||
GIT_COMMITTER_EMAIL = "your-email@example.com";
|
||||
# Commands to run when entering the shell
|
||||
shellHook = ''
|
||||
echo "Entering development shell for my project."
|
||||
echo "You have Git, Go, and Neovim available."
|
||||
'';
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
Now, from your project directory:
|
||||
|
||||
```bash
|
||||
nix develop
|
||||
```
|
||||
|
||||
You'll instantly find yourself in a shell where `git`, `go`, and `nvim` are available, and your `GIT_COMMITTER_EMAIL` is set. When you exit, your regular shell environment is restored – no lingering installations or modified global state. This makes it incredibly easy to switch between projects, each with its specific toolchain and dependencies, without conflicts.
|
||||
22
docs/introduction-to-nix/install-nix.md
Normal file
22
docs/introduction-to-nix/install-nix.md
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
# Install Nix
|
||||
|
||||
Install the Nix package manager according to the official documentation on [nixos.org](https://nixos.org/download/).
|
||||
|
||||
On Linux, simply run:
|
||||
|
||||
```bash
|
||||
sh <(curl --proto '=https' --tlsv1.2 -L https://nixos.org/nix/install) --daemon
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
Add the following to `~/.config/nix/nix.conf` (recommended) or `/etc/nix/nix.conf`:
|
||||
|
||||
```ini
|
||||
experimental-features = nix-command flakes
|
||||
```
|
||||
|
||||
- `nix-command` enables the [new `nix` CLI](https://nix.dev/manual/nix/2.29/command-ref/new-cli/nix.html) Nix is transitioning to.
|
||||
- `flakes` will be covered later in this guide. Don't worry about them for now.
|
||||
|
||||
Reload your session to get access to the `nix` command.
|
||||
227
docs/introduction-to-nix/nix-speedrun.md
Normal file
227
docs/introduction-to-nix/nix-speedrun.md
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
# Nix Speedrun
|
||||
|
||||
This section will cover some Nix language basics as fast as possible.
|
||||
|
||||
## Comments
|
||||
|
||||
```nix
|
||||
# This is a comment
|
||||
|
||||
/*
|
||||
This is a block comment
|
||||
*/
|
||||
```
|
||||
|
||||
## Data types
|
||||
|
||||
Every value in Nix has a type. Some basic types are:
|
||||
|
||||
```nix
|
||||
16 # integer
|
||||
|
||||
3.14 # float
|
||||
|
||||
false # boolean
|
||||
|
||||
"Hello, world!" # string
|
||||
|
||||
''
|
||||
This is also a string,
|
||||
but over multiple lines!
|
||||
''
|
||||
```
|
||||
|
||||
Assign a value to a variable:
|
||||
|
||||
```nix
|
||||
myVar = "99";
|
||||
```
|
||||
|
||||
And then inject it into a string:
|
||||
|
||||
```nix
|
||||
''
|
||||
I got ${myVar} problems,
|
||||
but Nix ain't one.
|
||||
''
|
||||
```
|
||||
|
||||
Nix also has compound values. This is a list:
|
||||
|
||||
```nix
|
||||
[ 123 "hello" true null [ 1 2 ] ]
|
||||
```
|
||||
|
||||
You can mix different types in a list. This is an attribute set:
|
||||
|
||||
```nix
|
||||
{
|
||||
foo = 4.56;
|
||||
bar = {
|
||||
baz = "this";
|
||||
qux = false;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
An attribute set is like an object. It is a collection of name-value-pairs called *attributes*. The expression above is equivalent to:
|
||||
|
||||
```nix
|
||||
{
|
||||
foo = 4.56;
|
||||
bar.baz = "this";
|
||||
bar.qux = false;
|
||||
}
|
||||
```
|
||||
|
||||
## Evaluation
|
||||
|
||||
In Nix, everything is an expression that evaluates to a value. Create a `hello.nix`-file with the following content:
|
||||
|
||||
```nix
|
||||
"Hello, world!"
|
||||
```
|
||||
|
||||
Then, evaluate the file:
|
||||
|
||||
```bash
|
||||
nix eval --file hello.nix
|
||||
```
|
||||
|
||||
```
|
||||
Hello, world!
|
||||
```
|
||||
|
||||
A let-expression allows you to define local variables for an expression:
|
||||
|
||||
```nix
|
||||
let
|
||||
alice = {
|
||||
name = "Alice";
|
||||
age = "26";
|
||||
};
|
||||
in
|
||||
''
|
||||
Her name is ${alice.name}.
|
||||
She is ${alice.age} years old.
|
||||
''
|
||||
```
|
||||
|
||||
## Functions
|
||||
|
||||
Functions have the following form:
|
||||
|
||||
```nix
|
||||
pattern: body
|
||||
```
|
||||
|
||||
The pattern specifies what the argument of the function must look like, and binds variables in the body to (parts of) the argument.
|
||||
|
||||
```nix
|
||||
let
|
||||
increment = num: num + 1;
|
||||
in
|
||||
increment 49
|
||||
```
|
||||
|
||||
Functions can only have a single argument. For multiple arguments, nest functions:
|
||||
|
||||
```nix
|
||||
let
|
||||
isAllowedToDrive =
|
||||
name: age:
|
||||
if age >= 18 then "${name} is eligible to drive." else "${name} is too young to drive yet.";
|
||||
in
|
||||
isAllowedToDrive "Charlie" 19
|
||||
```
|
||||
|
||||
It is common to pass multiple arguments in an attribute set instead. Since Nix is lazily evaluated, you can define multiple bindings in the same let-statement.
|
||||
|
||||
```nix
|
||||
let
|
||||
add = { a, b }: a + b;
|
||||
result = add { a = 34; b = 35; };
|
||||
in
|
||||
result
|
||||
```
|
||||
|
||||
You can also set optional arguments by providing default values:
|
||||
|
||||
```nix
|
||||
let
|
||||
greet = { greeting ? "Hello", name }: "${greeting}, ${name}!";
|
||||
in
|
||||
greet { name = "Bob"; }
|
||||
```
|
||||
|
||||
Let's look at one last example:
|
||||
|
||||
```nix
|
||||
let
|
||||
myFunc = { a, b, c }: a + b * c;
|
||||
|
||||
numbers = {
|
||||
a = 1;
|
||||
b = 2;
|
||||
c = 3;
|
||||
};
|
||||
|
||||
result = myFunc { a = numbers.a; b = numbers.b; c = numbers.c; };
|
||||
in
|
||||
result
|
||||
```
|
||||
|
||||
Nix provides some syntactical sugar to simplify that function call. The `with` keyword brings all attributes from an attribute set into the scope:
|
||||
|
||||
```nix
|
||||
# ...
|
||||
result = with numbers; myFunc { a = a; b = b; c = c; };
|
||||
# ...
|
||||
```
|
||||
|
||||
However, this syntax is discouraged. Use `inherit` instead to explicitly list attributes to bring into the scope:
|
||||
|
||||
```nix
|
||||
# ...
|
||||
inherit (numbers) a b c;
|
||||
result = myFunc { inherit a b c; };
|
||||
# ...
|
||||
```
|
||||
|
||||
## Builtin functions
|
||||
|
||||
Nix provides [builtin functions](https://nix.dev/manual/nix/2.25/language/builtins) by default through the global `builtins` constant. For example, `builtins.attrNames` gives you a list of all attributes of the given attribute set:
|
||||
|
||||
```nix
|
||||
builtins.attrNames { a = 1; b = 2; }
|
||||
# => [ "a" "b" ]
|
||||
```
|
||||
|
||||
> Yes, this means that attribute keys, though defined as variables, are available as strings.
|
||||
|
||||
Some builtins are so common that the `builtins` prefix can be omitted. `map` is a builtin function that applies a function to each element of a list.
|
||||
|
||||
```nix
|
||||
# squares.nix
|
||||
let
|
||||
numbers = [ 5 2 1 4 3 ];
|
||||
squares = map (n: n * n) numbers;
|
||||
in
|
||||
{
|
||||
inherit numbers squares;
|
||||
}
|
||||
```
|
||||
|
||||
The `import` function allows to separate the codebase into multiple files:
|
||||
|
||||
```nix
|
||||
# sort.nix
|
||||
let
|
||||
results = import ./squares.nix; # paths have their own type
|
||||
inherit (results) squares;
|
||||
inherit (builtins) sort lessThan;
|
||||
in
|
||||
sort lessThan squares
|
||||
```
|
||||
|
||||
> The `sort` function can be found in the [Nix manual](https://nix.dev/manual/nix/2.25/language/builtins#builtins-sort).
|
||||
40
docs/introduction-to-nix/nix-store.md
Normal file
40
docs/introduction-to-nix/nix-store.md
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
# Nix Store
|
||||
|
||||
You've built a package, and it landed in the `/nix/store`. The Nix store is the heart of Nix's reproducibility, atomicity, and rollback capabilities.
|
||||
|
||||
## Unique Paths (Hashing)
|
||||
|
||||
Every piece of software, configuration, or data managed by Nix lives in the Nix store under a unique, cryptographically hashed path. For example, `nix build` might produce something like:
|
||||
|
||||
```
|
||||
/nix/store/zx9qxw749wmla1fad93al7yw2mg1jvzf-my-hello-0.1.0
|
||||
```
|
||||
|
||||
A Nix store path consists of its hash and a human readable name with a version, which are defined in the corresponding derivation. The hash ensures:
|
||||
|
||||
1. **Immutability:** Entries in the Nix Store are read only. Once something is in the Nix store, it never changes. If you modify a source file or a build instruction, it creates a *new* derivation with a *new* hash, and thus a *new* path in the store. The old version remains untouched.
|
||||
2. **Reproducibility:** If two different systems build the exact same derivation, they will produce the exact same hash and thus the exact same path. This guarantees that "it works on my machine" translates to "it works on *any* Nix machine."
|
||||
3. **Collision Avoidance:** Because the path includes a hash of all its inputs (source code, build script, compiler, libraries, etc.), different versions or configurations of the same package can coexist peacefully in the store without conflicting.
|
||||
|
||||
You can inspect the contents of a store path directly:
|
||||
|
||||
```bash
|
||||
ls -l /nix/store/zx9qxw749wmla1fad93al7yw2mg1jvzf-my-hello-0.1.0/bin
|
||||
```
|
||||
|
||||
Replace the hash with the actual hash from your previous `nix build` command or `ls -l result`.
|
||||
|
||||
## Dependency Resolution
|
||||
|
||||
The Nix store is also a giant, explicit dependency graph.
|
||||
When you define a derivation for `my-hello` that uses `stdenv` and `gcc`, Nix doesn't just build `my-hello`. It first ensures that `stdenv` and `gcc` (and their own dependencies, recursively) are also present in the Nix store.
|
||||
|
||||
Let's look at the dependencies of your `my-hello` derivation:
|
||||
|
||||
```bash
|
||||
nix path-info --recursive ./result
|
||||
```
|
||||
|
||||
This command will list all the Nix store paths that `my-hello` directly or indirectly depends on. You'll see things like `glibc`, `gcc`, and many other low-level system libraries. Each of these is itself a derivation built and stored in the Nix store under its own unique hash.
|
||||
|
||||
This means that conflicts are impossible because different versions of the same library (e.g., `libssl-1.0` and `libssl-3.0`) can coexist peacefully in `/nix/store` under their distinct hashes.
|
||||
200
docs/introduction-to-nix/nixos.md
Normal file
200
docs/introduction-to-nix/nixos.md
Normal file
|
|
@ -0,0 +1,200 @@
|
|||
# NixOS
|
||||
|
||||
NixOS is a Linux distribution built entirely on top of the Nix package manager and the Nix language. This means your entire operating system, from the kernel to user-space applications and system services, is declared in a set of Nix expressions. This brings all the benefits of Nix (reproducibility, atomic upgrades, easy rollbacks) to your whole system.
|
||||
|
||||
## NixOS Configuration (with Flakes)
|
||||
|
||||
With flakes, your NixOS configuration typically resides in a `flake.nix` file that exports a `nixosConfigurations` output.
|
||||
|
||||
Let's have a look at a basic `flake.nix` for a NixOS machine.
|
||||
|
||||
```nix
|
||||
# flake.nix
|
||||
{
|
||||
inputs = {
|
||||
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
||||
};
|
||||
|
||||
outputs =
|
||||
{
|
||||
self, # The flake itself
|
||||
nixpkgs, # The nixpkgs input
|
||||
...
|
||||
}@inputs: # `self` and `nixpkgs` are available under `inputs`
|
||||
let
|
||||
inherit (self) outputs;
|
||||
in
|
||||
{
|
||||
# Define NixOS configurations
|
||||
nixosConfigurations = {
|
||||
# Name for this specific system configuration
|
||||
your-pc = nixpkgs.lib.nixosSystem {
|
||||
# Arguments passed to all NixOS modules
|
||||
specialArgs = {
|
||||
inherit inputs outputs;
|
||||
};
|
||||
# List of all configuration files (modules)
|
||||
modules = [ ./configuration.nix ];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
The `nixosSystem` function takes a list of `modules`. Each module is a Nix expression that defines desired system state and settings. So the actual system configuration lives in `configuration.nix`:
|
||||
|
||||
```nix
|
||||
# configuration.nix
|
||||
{ config, pkgs, ... }: # The arguments provided to a NixOS module
|
||||
|
||||
{
|
||||
# Enable a display manager and desktop environment
|
||||
services.displayManager.lightdm.enable = true;
|
||||
services.desktopManager.gnome.enable = true; # Or kde, xfce, etc.
|
||||
|
||||
# List of packages to be installed globally
|
||||
environment.systemPackages = with pkgs; [
|
||||
firefox
|
||||
neovim
|
||||
git
|
||||
];
|
||||
|
||||
# Configure networking
|
||||
networking.hostName = "my-nixos-desktop";
|
||||
|
||||
# Users
|
||||
users.users.Alice = {
|
||||
isNormalUser = true;
|
||||
extraGroups = [ "wheel" "networkmanager" ]; # Add user to groups for sudo and network management
|
||||
initialPassword = "changeme"; # Set a temporary password
|
||||
};
|
||||
|
||||
# Set system-wide locale
|
||||
i18n.defaultLocale = "en_US.UTF-8";
|
||||
|
||||
# Set the system time zone
|
||||
time.timeZone = "America/New_York";
|
||||
|
||||
# ... many more options ...
|
||||
}
|
||||
```
|
||||
|
||||
> Please note that the above configuration is not a complete working NixOS configuration. It just showcases how to you can define your system declaratively.
|
||||
|
||||
The `config` argument is the *evaluated* final configuration of your system. You use it to refer to other parts of your configuration. For example, you might make one service depend on another's path:
|
||||
|
||||
```nix
|
||||
myService.dataPath = config.services.otherService.dataPath;
|
||||
```
|
||||
|
||||
It's primarily used for referencing options *within* the configuration.
|
||||
|
||||
## The Module System
|
||||
|
||||
NixOS uses a powerful *module system*. A module is a Nix expression that declares:
|
||||
|
||||
- **`options`**: What configurable parameters this module exposes.
|
||||
- **`config`**: How this module sets those parameters (and potentially other system parameters).
|
||||
- **`imports`**: Other modules to include.
|
||||
|
||||
When you build your NixOS configuration using `nixos-rebuild switch --flake path/to/flake/directory#your-pc`, NixOS collects all the options and configurations from all activated modules, merges them, and then builds a new system closure in the Nix store.
|
||||
|
||||
## Searching NixOS Options
|
||||
|
||||
There are thousands of options in NixOS. You can search them in the [NixOS Options Search](https://search.nixos.org/options?channel=unstable).
|
||||
|
||||
For example, search for `services.desktopManager` to list all options regarding desktop managers.
|
||||
|
||||
## Home Manager
|
||||
|
||||
While NixOS manages system-wide configurations, **Home Manager** applies the power of Nix to your *user-specific* configuration files and dotfiles. Instead of manually symlinking dotfiles or writing install scripts, you define your user environment declaratively in Nix. Home Manager applies Nix's declarative power to the user space, much like NixOS does for the system space.
|
||||
|
||||
Let's extend our `flake.nix`:
|
||||
|
||||
```nix
|
||||
# flake.nix
|
||||
{
|
||||
inputs = {
|
||||
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
||||
|
||||
home-manager.url = "github:nix-community/home-manager";
|
||||
home-manager.inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
outputs =
|
||||
{
|
||||
self,
|
||||
nixpkgs,
|
||||
home-manager,
|
||||
...
|
||||
}@inputs:
|
||||
let
|
||||
inherit (self) outputs;
|
||||
in
|
||||
{
|
||||
nixosConfigurations = {
|
||||
your-pc = nixpkgs.lib.nixosSystem {
|
||||
specialArgs = {
|
||||
inherit inputs outputs;
|
||||
};
|
||||
modules = [ ./configuration.nix ];
|
||||
};
|
||||
};
|
||||
|
||||
homeConfigurations = {
|
||||
your-user = home-manager.lib.homeManagerConfiguration {
|
||||
pkgs = nixpkgs.legacyPackages.x86_64-linux;
|
||||
extraSpecialArgs = {
|
||||
inherit inputs outputs;
|
||||
};
|
||||
modules = [ ./home.nix ];
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
`home.nix` might look like this:
|
||||
|
||||
```nix
|
||||
# home.nix
|
||||
{ config, pkgs, ... }:
|
||||
|
||||
{
|
||||
# Define your user's home directory
|
||||
home.username = "youruser";
|
||||
home.homeDirectory = "/home/youruser";
|
||||
|
||||
# Install user-specific packages
|
||||
home.packages = with pkgs; [
|
||||
htop
|
||||
cowsay
|
||||
];
|
||||
|
||||
# Configure zsh
|
||||
programs.zsh.enable = true;
|
||||
programs.zsh.ohMyZsh.enable = true;
|
||||
programs.zsh.ohMyZsh.plugins = [ "git" "history" ];
|
||||
|
||||
# Git configuration
|
||||
programs.git = {
|
||||
enable = true;
|
||||
userName = "Your Name";
|
||||
userEmail = "your.email@example.com";
|
||||
};
|
||||
|
||||
# ... many more options for things like VS Code, Tmux, themes, fonts etc.
|
||||
}
|
||||
```
|
||||
|
||||
You could now build your Home Manager configuration with `home-manager switch --flake path/to/flake/directory#your-user`.
|
||||
|
||||
Search for Home Manager options in the [Home Manager Options Search](https://home-manager-options.extranix.com/?release=master).
|
||||
|
||||
## What synix does
|
||||
|
||||
The [`synix` repository](https://git.sid.ovh/sid/synix) attempts to automate your NixOS and Home Manager experience. It exposes NixOS and Home Manager modules that sit on top of the already existing modules in NixOS and Home Manager respectively. Module options are added and opinionated defaults are set to get your configuration running with less configuration options needed to be set.
|
||||
|
||||
Create your NixOS and Home Manager configuration flake (we call that `nix-config`) with synix as an input using a template provided in the repository. Adding NixOS and Home Manager configurations is automated through a shell script. You can choose between some configuration templates for server or client systems. The installation process is automated through a shell script as well. Also, an installation guide is provided. Rebuilding your NixOS and Home Manager configurations is wrapped in synix's rebuild script.
|
||||
|
||||
The [Getting Started Guide](../getting-started/create-nix-config.md) will take you from nothing to a working NixOS configuration using synix.
|
||||
BIN
docs/introduction-to-nix/nixpkgs-firefox.png
Normal file
BIN
docs/introduction-to-nix/nixpkgs-firefox.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 114 KiB |
84
docs/introduction-to-nix/nixpkgs.md
Normal file
84
docs/introduction-to-nix/nixpkgs.md
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
# Nixpkgs
|
||||
|
||||
`Nixpkgs` is the massive collection of Nix expressions that define essentially *all* software available for Nix. It's the standard library for Nix, containing tens of thousands of packages. When you interact with `nixpkgs` in your Nix expressions, you're using this vast resource.
|
||||
|
||||
## How to Get Packages from Nixpkgs
|
||||
|
||||
The simplest way to use a package from Nixpkgs is to import it:
|
||||
|
||||
```bash
|
||||
nix eval --impure --expr 'with import <nixpkgs> {}; pkgs.hello'
|
||||
```
|
||||
|
||||
This evaluates an expression that imports Nixpkgs and makes its contents available as `pkgs`. The result will be a Nix store path for the `hello` package derivation.
|
||||
|
||||
You can also use `nix build`:
|
||||
|
||||
```bash
|
||||
nix build nixpkgs#hello
|
||||
```
|
||||
|
||||
This will build and symlink `hello` into your current directory as `result`.
|
||||
|
||||
And `nix run`:
|
||||
|
||||
```bash
|
||||
nix run nixpkgs#hello/bin/hello
|
||||
```
|
||||
```
|
||||
Hello, world!
|
||||
```
|
||||
|
||||
> You could also run `./result/bin/hello`.
|
||||
|
||||
This command tells Nix to run the `hello` executable from the `hello` package in Nixpkgs.
|
||||
|
||||
## Searching Nixpkgs
|
||||
|
||||
You can search for packages directly from your terminal:
|
||||
|
||||
```bash
|
||||
nix search nixpkgs firefox
|
||||
```
|
||||
|
||||
This command will list all packages in your Nixpkgs channel that contain "firefox" in their name or description. You'll likely see results like `firefox` and `firefox-bin`.
|
||||
|
||||
However, the CLI is slow and not convenient to use. You should use the [Nixpkgs search](https://search.nixos.org/packages?channel=unstable) instead.
|
||||
|
||||
This is the entry of Firefox in Nixpkgs:
|
||||
|
||||

|
||||
|
||||
### How to install *firefox*?
|
||||
|
||||
You can use Nix as a traditional package manager:
|
||||
|
||||
```bash
|
||||
nix-env -iA nixpkgs.firefox
|
||||
```
|
||||
|
||||
This is **not recommended** as packages installed this way must be updated and maintained by the user in the same way as with a traditional package manager. To temporarily install a package for testing purposes, use `nix-shell` instead:
|
||||
|
||||
```bash
|
||||
nix-shell -p firefox
|
||||
```
|
||||
|
||||
This will spawn a shell with `firefox` available. To permanently install a package with Nix, add it to your NixOS or Home Manager configuration. NixOS and Home Manager will be covered later in this guide.
|
||||
|
||||
## `pkgs.lib` utility functions
|
||||
|
||||
The `pkgs` argument (or `nixpkgs` itself) isn't just a list of applications; it also provides a powerful utility library called `pkgs.lib`. This library contains helper functions for working with Nix expressions, strings, lists, and more.
|
||||
|
||||
Many of these functions are used extensively within Nixpkgs itself to define packages and modules. You can browse the full [`pkgs.lib` documentation online](https://nixos.org/manual/nixpkgs/stable/#sec-functions-library) for more details.
|
||||
|
||||
## The Nixpkgs GitHub Repository
|
||||
|
||||
Nixpkgs is an open-source project hosted on GitHub: [github.com/NixOS/nixpkgs](https://github.com/NixOS/nixpkgs). You can explore its source code to see how packages are defined. Every package definition is a Nix expression!
|
||||
|
||||
For example, you could find the definition for `hello` at `pkgs/by-name/he/hello/package.nix`. It uses `stdenv.mkDerivation` just like our example.
|
||||
|
||||
## Binary Caches
|
||||
|
||||
Building everything from source every time can be slow. Nix solves this with **binary caches**. When someone builds a derivation, if that exact derivation (with its exact hash) has already been built and uploaded to a binary cache (like [`cache.nixos.org`](https://cache.nixos.org/)), Nix will simply *download* the pre-built binaries from the cache instead of building it locally.
|
||||
|
||||
This is possible because of the unique hashing of store paths. If the hash matches, the content *must* be identical, so a downloaded binary is guaranteed to be the same as one built locally. This significantly speeds up package installation and system updates.
|
||||
9
docs/introduction-to-nix/overview.md
Normal file
9
docs/introduction-to-nix/overview.md
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
# Introduction to Nix
|
||||
|
||||
Welcome to the world of Nix! This guide aims to take you from a complete beginner to confidently using Nix for reproducible development environments and even managing your entire operating system with NixOS.
|
||||
|
||||
Nix is a powerful package manager that brings functional programming principles to system configuration. This means your builds are reproducible, changes are atomic, and rollbacks are easy. Forget "it works on my machine" – with Nix, it works everywhere.
|
||||
|
||||
We'll start with the fundamentals of the Nix language, then explore how Nix builds software. From there, we'll dive into the massive Nixpkgs collection, cover how Nix ensures reproducibility with flakes, and finally, show you how to manage your entire system with NixOS.
|
||||
|
||||
Let's begin!
|
||||
Loading…
Add table
Add a link
Reference in a new issue