Packages

Package Ecosystem & Customization

A multi-layered package management strategy combining standard Nixpkgs with local extensions and overlays.

📦 The Package Hierarchy

This repository manages packages through three distinct layers:

1. Nixpkgs (The Base)

We primarily track nixos-unstable for the latest hardware support and software features. Standard packages are accessed via the global pkgs attribute.

2. Local Packages (hey.packages)

Custom derivations located in the packages/ directory are automatically scanned and exposed under the hey.packages namespace.

  • Exposure: Handled by flake.nix and lib/nixos.nix.
  • Purpose: Ideal for small utilities (like betterfox) that aren’t in upstream Nixpkgs or require specialized versions.
  • Usage: Always prefer hey.packages.name for files inside this repo to ensure reproducibility.

3. Overlays (overlays/)

Overlays allow us to modify existing packages in Nixpkgs globally.

Static Overlays (directory-based)

Every file in overlays/ is automatically imported and applied to the pkgs set via mapModules ./overlays import in flake.nix. Example: overriding a kernel version or fixing a broken library across all applications.

Module-Level Overlays (nixpkgs.overlays)

For overlays tied to a specific feature module, use the NixOS nixpkgs.overlays option directly in the module config — no need to touch flake.nix:

# modules/dev/rust.nix
nixpkgs.overlays = [
  hey.inputs.rust-overlay.overlays.default
];
# modules/editors/default.nix
nixpkgs.overlays = [
  hey.inputs.nix-vscode-extensions.overlays.default
];

This pattern keeps the overlay self-contained with the module that needs it and ensures it inherits the system nixpkgs config (e.g. allowUnfree = true). It works even when nixpkgs.pkgs is externally provided — NixOS applies module-level overlays via pkgs.appendOverlays.


🛠️ Custom Packages Logic

The mapModules Pipeline

We use a custom library function to auto-load packages:

packages = mapModules ./packages import;

This means adding a new package is as simple as creating a folder in packages/ with a default.nix.

Versions & Determinism

For local packages that fetch from GitHub (like betterfox), we use fetchFromGitHub with explicit commit hashes and sha256 SRI hashes. This guarantees that your environment stays identical regardless of when or where it is built.


🏗️ Stable vs. Unstable

Our flake includes a nixpkgs-stable input. In rare cases where a package is broken on unstable, we can access the stable version via pkgs.pkgs-stable.<name>. This is implemented as a global overlay in lib/nixos.nix.


🛠️ Developer: Local Package Lifecycle

When adding or updating a package in packages/, follow this “Surgical Iteration” workflow to avoid slow rebuilds.

1. Isolated Build Test

Don’t run hey sync to test a package change. Build it in isolation using a temporary expression:

nix-build -E 'with import <nixpkgs> {}; callPackage ./packages/your-pkg/default.nix { self = {}; }'

Note: If the package requires specific overrides (like rofi-wayland), pass them in the attribute set.

2. Idiomatic Patching: substituteInPlace

Avoid using .patch files for simple path redirections. Patches are brittle and break when upstream line numbers change. Use substituteInPlace in the postPatch phase:

postPatch = ''
  substituteInPlace configure.ac \
    --replace-fail '[PLUGIN_DIR]="`$PKG_CONFIG --variable=pluginsdir rofi`"' \
                   '[PLUGIN_DIR]="$out/lib/rofi"'
'';

This is “Search & Replace” for your source code, making it resilient to version bumps.

3. Pruning Broken Upstream Logic

If an upstream update breaks secondary components (like a test suite or documentation generator), don’t revert. Prune it in prePatch:

prePatch = ''
  # Skip building broken tests
  sed -i 's/SUBDIRS = src tests/SUBDIRS = src/' Makefile.am
  sed -i 's/tests\/Makefile//' configure.ac
'';

🚀 Adding a Local Package

  1. Create packages/<your-pkg>/default.nix.
  2. Write a standard Nix derivation.
  3. It will be immediately available as hey.packages.<your-pkg> in any module.
  4. If you want it available globally as just <your-pkg>, add an overlay in overlays/.