Flakes
Nix Flakes are an essential part of the Nix ecosystem, offering a more reproducible, composable, and declarative approach to package management. Here's a comprehensive overview with examples:
Overview
- Purpose: Flakes provide a hermetic, reproducible, and declarative way to manage Nix packages, projects, and configurations.
- Components:
- Flake.nix: Central to any flake, this file declares inputs (dependencies), outputs (packages, applications), and how to build them.
- Lock File: Ensures reproducibility by pinning the exact version of each input.
This file is called
flake.lock
Basic Structure
A simple flake.nix might look like this:
{
description = "A simple Nix flake example";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
};
outputs = { self, nixpkgs }: {
defaultPackage.x86_64-linux = nixpkgs.legacyPackages.x86_64-linux.hello;
};
}
This is the same example from the previous chapter
Using Flakes
- Creating a New Flake: Initialize a new flake in a directory with
nix flake init. - Building a Flake: Use
nix buildto build the flake's default package. - Updating Flake Inputs: Run
nix flake updateto update the inputs according to the lock file.
Example: Packaging an Application
Here's an example of packaging a simple application with a flake:
{
description = "My Application";
inputs = {
nixpkgs.url = "nixpkgs/nixos-unstable";
};
outputs = { self, nixpkgs }: {
packages.x86_64-linux.myapp = nixpkgs.stdenv.mkDerivation {
name = "myapp";
src = ./.;
buildInputs = [ nixpkgs.gcc nixpkgs.make ];
buildPhase = ''
make
'';
installPhase = ''
mkdir -p $out/bin
cp myapp $out/bin/
'';
};
};
}
Advanced Usage
- Overlays: Customize packages from
nixpkgsusing overlays. - Custom Inputs: Include other flakes as inputs.
- Cross-Compilation: Support for cross-compiling to different platforms.
Best Practices
- Version Control: Keep your
flake.nixandflake.lockunder version control. - Modularity: Create modular and reusable components.
- Documentation: Document the purpose and usage of your flakes.
Limitations
- Compatibility: Not all Nix packages, libraries, or configurations have been converted to flakes.
- Not all features related to flakes are stable yet
Examples of derivations
Derivations are Nix's counterpart to packages (and also sometimes intermediary build steps leading to packages!).
Many language-specific libraries, such as crane provide wrappers which construct derivations for you.
The simplest way to create a derivation is to use the mkDerivation function:
Example 1: Basic C Application
{
description = "A simple C application";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-21.05";
};
outputs = { self, nixpkgs }: {
packages.x86_64-linux.myCApp = nixpkgs.stdenv.mkDerivation {
pname = "myCApp";
version = "1.0";
src = ./.;
buildInputs = [ nixpkgs.gcc ];
};
};
}
Example 2: Python Application with Custom Phases
{
description = "A Python application";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-21.05";
};
outputs = { self, nixpkgs }: {
packages.x86_64-linux.myPythonApp = nixpkgs.stdenv.mkDerivation {
pname = "myPythonApp";
version = "1.0";
src = ./.;
buildInputs = [ nixpkgs.python3 ];
buildPhase = ''
python3 setup.py build
'';
installPhase = ''
python3 setup.py install --prefix=$out
'';
};
};
}
Example 3: Application with Custom Patches and Post-Install
{
description = "An application with custom patches";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-21.05";
};
outputs = { self, nixpkgs }: {
packages.x86_64-linux.myPatchedApp = nixpkgs.stdenv.mkDerivation {
pname = "myPatchedApp";
version = "1.0";
src = ./.;
patches = [ ./fix-bug.patch ./add-feature.patch ];
postInstall = ''
echo "Post-install actions here"
'';
};
};
}
Example 4: Application with Pre-Configured and Post-Build Steps
{
description = "Application with pre- and post-build steps";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-21.05";
};
outputs = { self, nixpkgs }: {
packages.x86_64-linux.myComplexApp = nixpkgs.stdenv.mkDerivation {
pname = "myComplexApp";
version = "1.0";
src = ./.;
preConfigure = ''
echo "Pre-configuration actions here"
'';
postBuild = ''
echo "Post-build actions here"
'';
};
};
}
Some important fields in mkDerivation:
pname: Package name.version: Package version.src: Source of the package, often the current directory (./.).buildInputs: List of dependencies required to build the package.buildPhase,installPhase,preConfigure,postInstall,postBuild: Custom phases to control different stages of the build process.patches: List of patches to be applied to the source.