nixpkgs-package-from-flake-fork¶
Overlays
Rebuild any nixpkgs package from your own fork of its source — carried as a
flake input — with a one-line overrideAttrs overlay. You keep everything
nixpkgs already did to package it (wrappers, build inputs, passthru, platform
handling) and swap only the source tree and version.
The problem¶
You maintain a fork of some upstream project (a rebrand, a backported fix, a feature branch) and you want your NixOS/home-manager config to build that, not the pinned upstream release nixpkgs ships. Writing a fresh derivation means re-deriving all the packaging that nixpkgs already got right. You don't want to own that — you only want to redirect the source.
The insight¶
prev.<pkg>.overrideAttrs lets you replace just src (and version) while
inheriting the rest of nixpkgs' derivation. Point src straight at the flake
input holding your fork and three details fall out:
-
Version from the revision. A flake input exposes
shortRev, soversion = "${prefix}-${src.shortRev or "dev"}"gives every build a meaningful, fork-labelled version with zero manual bumping. Theor "dev"fallback matters:shortRevis absent for dirty local trees and somenix flake checkpaths, and without the fallback those evaluations throw. -
Tests off by default (
doCheck = false). This is the main trap. A fork's test suite almost always diverges from upstream's — renamed cases, dropped fixtures, different assumptions — so nixpkgs' check phase fails for reasons unrelated to your change. Unless you actively maintain the fork's tests, leave checks off. -
Clear patches when the fork already carries them (
clearPatches = true). If your fork already includes the patches nixpkgs applies on top of upstream, nixpkgs will try to apply them again against a tree that already has them — and fail on already-applied hunks. SetclearPatches = trueto hand all patching to your fork.
Usage¶
# flake.nix
{
inputs.my-app-fork.url = "github:you/app-fork/my-branch";
# ... in your nixpkgs config / colmena / nixosConfigurations:
nixpkgs.overlays = [
(import ./overlays/nixpkgs-package-from-flake-fork {
pname = "someapp"; # attribute name in nixpkgs
src = inputs.my-app-fork; # your fork, passed as a flake input
})
];
}
That's it — pkgs.someapp now builds from your fork, versioned
fork-<shortRev>.
Options¶
| Option | Default | Purpose |
|---|---|---|
pname |
required | Attribute name of the package in nixpkgs. |
src |
required | The flake input holding your fork (used as src and to derive the version). |
versionPrefix |
"fork" |
Prefix on the derived version string, so --version output makes the fork obvious. |
doCheck |
false |
Run the check/installCheck phases. Turn on only if you maintain the fork's tests. |
clearPatches |
false |
Drop nixpkgs' patches. Set when your fork already carries them. |
Caveats¶
-
Passthru overrides.
overrideAttrsruns onprev.<pkg>, so it does not see later overlays. If a downstream override must still apply (e.g. another overlay swaps a dependency), apply this overlay first or usefinal.callPackagemachinery instead. -
srcmust match the derivation's build assumptions. You're only swapping the source; the build phases, dependencies, and directory layout still come from nixpkgs. If your fork restructures the tree or changes the build system, a source swap alone won't be enough — you'll need a fuller override. -
Version string is cosmetic.
versionhere is just a label; it does not gate anything. Some packages embed their own version at build time from the source, which will show independently.
Source¶
overlays/nixpkgs-package-from-flake-fork/default.nix
# Rebuild any nixpkgs package from your own flake-input fork.
#
# This is a reusable overlay factory. You point `src` at a flake input that
# holds your fork of a package's upstream source, and it rebuilds the nixpkgs
# derivation of that package against your tree — keeping every other build
# input, wrapper, and passthru that nixpkgs already wired up.
#
# Why an overlay factory and not a hand-written derivation: nixpkgs packages
# often carry a lot of build machinery (wrappers, patches, passthru, checks,
# platform handling). `overrideAttrs` lets you swap ONLY the source and version
# while inheriting all of that, so you track upstream's packaging for free.
#
# Usage (flake.nix):
#
# inputs.my-app-fork.url = "github:you/app-fork/my-branch";
#
# overlays = [
# (import ./overlays/nixpkgs-package-from-flake-fork {
# pname = "someapp"; # attribute name in nixpkgs
# src = inputs.my-app-fork; # your fork, as a flake input
# })
# ];
#
# The overlay is a plain `final: prev:` function, so it composes with any other
# overlay and works anywhere nixpkgs overlays are accepted.
{
# Attribute name of the package in nixpkgs, e.g. "someapp".
pname,
# The flake input holding your fork. A flake source exposes `shortRev` (and
# `rev`), which we use to derive a version string. Passing the input directly
# as `src` also pins the build to that exact revision.
src,
# Label prefixed to the derived version string. Use it to make it obvious in
# `nix-store -q` / `--version` output that this is your fork, not upstream.
versionPrefix ? "fork",
# Your fork's test suite may diverge from upstream's (renamed tests, dropped
# fixtures, different assumptions). Leaving checks ON will usually fail the
# build for reasons that have nothing to do with your change, so this defaults
# to false. Flip to true only if you actively maintain the fork's tests.
doCheck ? false,
# Set true when your fork already carries the patches nixpkgs applies on top of
# upstream — otherwise nixpkgs' patches will fail to apply against your tree
# (already-applied hunks) or double-apply. Clearing `patches` hands patching
# responsibility entirely to your fork.
clearPatches ? false,
}:
final: prev:
{
${pname} = prev.${pname}.overrideAttrs (old:
{
# `shortRev` is only present when the input is a clean git/flake ref; the
# `or "dev"` fallback keeps `nix flake check` and dirty local trees working.
version = "${versionPrefix}-${src.shortRev or "dev"}";
src = src;
}
// (if doCheck then { } else { doCheck = false; doInstallCheck = false; })
// (if clearPatches then { patches = [ ]; } else { })
);
}