Skip to content

Nix Flakes Why?

The difference between “Flakes” and “just Nix” (referring to the traditional, pre-flakes way of using Nix) is substantial, and it addresses some of the core challenges that made older Nix harder to use and less reliable. Here’s a detailed breakdown:

Reproducibility and Impurity

  • Traditional Nix (Impure by Default):

    • Relied heavily on NIX_PATH, an environment variable that tells Nix where to find Nix expressions (like nixpkgs).
    • NIX_PATH‘s variability (global, per-user, per-project) meant the same Nix expression could produce different results. This caused “it works on my machine” problems.
    • Nix expressions could “leak” dependencies from the system (files, environment variables), hindering truly isolated, reproducible builds.
    • Channels (e.g., nixos-unstable) managed nixpkgs versions, but were mutable. Channel updates could break builds.
  • Flakes (Reproducible by Design):

    • No NIX_PATH Dependence: Flakes use explicit, declarative inputs in flake.nix, specifying exact dependency versions.
    • flake.lock: Pins inputs to specific versions (Git commits, tarball hashes), guaranteeing identical dependencies for all users.
    • Purity: Flakes are evaluated in a much more isolated environment, preventing accidental dependencies on external files or environment variables. This is crucial for reproducibility. Impurity is still possible (e.g., with builtins.getEnv), but is more explicit and avoidable.
    • No Channels (for Flakes): Replaces channels with direct Git repository references (or other sources) and their commits. This is more precise and avoids mutable channel problems.

Project Structure and Discoverability

  • Traditional Nix:

    • No standard project structure. Nix expressions could be scattered (default.nix, release.nix, etc.), making project understanding difficult.
    • Discovering available packages/configurations was ad-hoc. You had to read the Nix expressions.
  • Flakes:

    • flake.nix Standard: Every flake has a flake.nix at its root, describing inputs and outputs consistently.
    • nix flake show: Standard way to discover available outputs (packages, configurations, etc.) without reading Nix code.
    • Well-defined outputs: Flakes have conventional output attributes (packages, devShell, nixosConfigurations), clarifying what a flake provides.

Development Environments

  • Traditional Nix:

    • nix-shell created development environments, often configured with shell.nix. But shell.nix often had the same impurity problems as other Nix expressions.
    • nix-shell could be slow for large projects due to re-evaluations.
  • Flakes:

    • nix develop: Uses the devShell output of a flake for reproducible development environments. The environment is defined in flake.nix and locked by flake.lock, ensuring consistency.
    • nix develop is generally faster than nix-shell due to improved caching and evaluation.
    • Clean Separation: Development environment is a separate output, simplifying management and understanding.

NixOS Configuration

  • Traditional NixOS:

    • System configurations typically lived in /etc/nixos/configuration.nix. This file could contain imperative code and be difficult to manage.
    • System updates (nixos-rebuild switch) could be risky, potentially breaking the system.
  • Flakes with NixOS:

    • nixosConfigurations Output: Flakes define entire NixOS system configurations as outputs, enabling declarative, reproducible system management.
    • nixos-rebuild switch --flake .#my-config: Build and switch to a specific configuration, ensuring you use the exact system version defined in the flake.
    • Atomic Updates: NixOS deployments with flakes are atomic. Either the entire new configuration is applied, or the system rolls back, significantly reducing the risk of a broken system.

Command-Line Interface

  • Traditional Nix: nix-* commands (nix-env, nix-build, nix-shell) had an inconsistent and sometimes confusing interface.

  • Flakes: The nix command (with experimental features enabled) provides a more unified and consistent CLI for working with flakes, designed for user-friendliness.

Caching

  • Both: Both traditional Nix and Flakes use caching to speed up builds.
  • Flakes (Improved Caching): Flakes generally have better caching due to more precise input tracking and evaluation. This leads to faster builds, especially for incremental changes. The lockfile facilitates sharing cached build results between machines.

Versioning and Updates

  • Traditional Nix: Relied on updating channels, which could lead to unexpected breakages.
  • Flakes: nix flake update explicitly updates the lock file, giving precise control over dependency versions.

In Summary: Key Advantages of Flakes

Flakes represent a significant improvement over traditional Nix, offering:

  • True Reproducibility: Eliminates “works on my machine” problems.
  • Declarative Management: Easier to understand and manage dependencies.
  • Standardized Structure: Improves project organization and discoverability.
  • Improved Development Workflows: Better way to create and manage dev environments.
  • Safer NixOS Configuration: More reliable NixOS system management.
  • Unified CLI: A more user-friendly command-line experience.

Flakes are highly recommended for new Nix projects and are increasingly adopted by existing projects due to these benefits.

Page last modified: 2025-02-27 16:35:42