Understanding_package_definitions
Understanding Package Definitions in Nix

In Nix, the concept of a package can refer to two things:
A collection of files and data that constitute a piece of software or an artifact.
A Nix expression that describes how to create such a collection. This expression acts as a blueprint before the package exists in a tangible form.
The process begins with writing a package definition using the Nix language. This definition contains the necessary instructions and metadata about the software you intend to “package.”
The Journey from Definition to Package
Package Definition:
This is essentially a function written in the Nix language.
Nix language shares similarities with JSON but includes the crucial addition of functions.
It acts as the blueprint for creating a package.
Derivation:
When the package definition is evaluated by Nix, it results in a derivation.
A derivation is a concrete and detailed build plan.
It outlines the exact steps Nix needs to take: fetching source code, building dependencies, compiling code, and ultimately producing the desired output (the package).
Realization (Building the Package):
You don’t get a pre-built “package” directly from the definition or the derivation.
The package comes into being when Nix executes the derivation. This process is often referred to as “realizing” the derivation.
Analogy: Think of a package definition as an architectural blueprint, the derivation as the detailed construction plan, and the realized package as the finished building.
Skeleton of a Derivation
The most basic derivation structure in Nix looks like this:
{ stdenv }:
stdenv.mkDerivation { }
This is a function that expects an attribute set containing
stdenv
as its argument.It then calls
stdenv.mkDerivation
(a function provided bystdenv
) to produce a derivation.Currently, this derivation doesn’t specify any build steps or outputs.
Further Reading:
Example: A Simple “Hello” Package Definition
Here’s a package definition for the classic “hello” program:
# hello.nix
{
stdenv,
fetchzip,
}:
stdenv.mkDerivation {
pname = "hello";
version = "2.12.1";
src = fetchzip {
url = "[https://ftp.gnu.org/gnu/hello/hello-2.12.1.tar.gz](https://ftp.gnu.org/gnu/hello/hello-2.12.1.tar.gz)";
sha256 = "";
};
}
This is a Nix function that takes stdenv and fetchzip as arguments.
It uses
stdenv.mkDerivation
to define the build process for the “hello” package.pname
: The package name.version
: The package version.src
: Specifies how to fetch the source code usingfetchzip
.
Handling Dependencies: Importing Nixpkgs
If you try to build
hello.nix
directly withnix-build hello.nix
, it will fail becausestdenv
andfetchzip
are part of Nixpkgs, which isn’t included in this isolated file.To make this package definition work, you need to pass the correct arguments (
stdenv
,fetchzip
) to the function.
The recommended approach is to create a default.nix
file in the same
directory:
# default.nix
let
nixpkgs = fetchTarball "[https://github.com/NixOS/nixpkgs/tarball/nixos-24.05](https://github.com/NixOS/nixpkgs/tarball/nixos-24.05)";
pkgs = import nixpkgs { config = {}; overlays = []; };
in
{
hello = pkgs.callPackage ./hello.nix { };
}
This
default.nix
imports Nixpkgs.It then uses
pkgs.callPackage
to call the function inhello.nix
, passing the necessary dependencies from Nixpkgs.You can now build the “hello” package using:
nix-build -A hello
. The-A
flag tells Nix to build the attribute named hello from the top-level expression in default.nix.
Realizing the Derivation and Handling sha256
Evaluation vs. Realization: While “evaluate” refers to Nix processing an expression, “realize” often specifically means building a derivation and producing its output in the Nix store.
When you first run
nix-build -A hello
, it will likely fail due to a missing sha256 hash for the source file. Nix needs this hash for security and reproducibility. The error message will provide the correct sha256 value.Example Error):
nix-build -A hello
error: hash mismatch in fixed-output derivation '/nix/store/pd2kiyfa0c06giparlhd1k31bvllypbb-source.drv':
specified: sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
got: sha256-1kJjhtlsAkpNB7f6tZEs+dbKd8z7KoNHyDHEJ0tmhnc=
error: 1 dependencies of derivation '/nix/store/b4mjwlv73nmiqgkdabsdjc4zq9gnma1l-hello-2.12.1.drv' failed to build
- Replace the empty
sha256 = "";
inhello.nix
with the provided correct value:sha256 = "1kJjhtlsAkpNB7f6tZEs+dbKd8z7KoNHyDHEJ0tmhnc=";
.
Building and Running the Result
After updating the sha256
, you can successfully build the package:
nix-build -A hello
The output will be a result symlink pointing to the built package in the Nix store. You can then run the “hello” program:
./result/bin/hello
Hello, world!
Swaytools Package Definition
Example: The swaytools Package Definition
Let’s examine a more complex, real-world package definition from Nixpkgs:
nixpkgs/pkgs/tools/wayland/swaytools/default.nix
.
# default.nix
{
lib,
setuptools,
buildPythonApplication,
fetchFromGitHub,
slurp,
}:
buildPythonApplication rec {
pname = "swaytools";
version = "0.1.2";
format = "pyproject";
src = fetchFromGitHub {
owner = "tmccombs";
repo = "swaytools";
rev = version;
sha256 = "sha256-UoWK53B1DNmKwNLFwJW1ZEm9dwMOvQeO03+RoMl6M0Q=";
};
nativeBuildInputs = [ setuptools ];
propagatedBuildInputs = [ slurp ];
meta = with lib; {
homepage = "https://github.com/tmccombs/swaytools";
description = "Collection of simple tools for sway (and i3)";
license = licenses.gpl3Only;
maintainers = with maintainers; [ atila ];
platforms = platforms.linux;
};
}
Breakdown of the Above default.nix
1 Function Structure:
- The file starts with a function taking an attribute set of dependencies from
Nixpkgs:
{ lib, setuptools, buildPythonApplication, fetchFromGitHub, slurp }
:.
- Derivation Creation:
- It calls
buildPythonApplication
, a specialized helper for Python packages (similar tostdenv.mkDerivation
but pre-configured for Python). Therec
keyword allows attributes within the derivation to refer to each other.
- Package Metadata:
pname
andversion
define the package’s name and version.The
meta
attribute provides standard package information like the homepage, description, license, maintainers, and supported platforms.
- Source Specification:
- The
src
attribute usesfetchFromGitHub
to download the source code from the specified repository and revision, along with itssha256
hash for verification.
- Build and Runtime Dependencies:
nativeBuildInputs
: Lists tools required during the build process (e.g.,setuptools
for Python).propagatedBuildInputs
: Lists dependencies needed at runtime (e.g.,slurp
).
- Build Format:
format = "pyproject";
indicates that the package uses apyproject.toml
file for its Python build configuration.
Integration within Nixpkgs
Location: The swaytools definition resides in
pkgs/tools/wayland/swaytools/default.nix
.Top-Level Inclusion: It’s made available as a top-level package in
pkgs/top-level/all-packages.nix
like this:
# all-packages.nix
swaytools = python3Packages.callPackage ../tools/wayland/swaytools { };
python3Packages.callPackage
is used here becauseswaytools
is a Python package, and it ensures the necessary Python-related dependencies are correctly passed to theswaytools
definition.