This commit is contained in:
commit
95a533c876
451 changed files with 18255 additions and 0 deletions
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.
|
||||
Loading…
Add table
Add a link
Reference in a new issue