One of the great features of Nix users here is the ability to run multiple versions of software at the same time; they know it’s possible, but putting into practice can be a bit trickier. A common use case is to keep your base setup on the tried nixos-YY.MM stable version, but keep some specific tooling — like that of a the language coding in — using nixpkgs-unstable for instance to have the freshest compiler & tooling for $PROGRAMMING_LANGUAGE. While this guide isn’t that specific to Nixtamal itself, it’s still worth writing about for our context.

The Great Nixpkgs Composer

Old heads & seasoned user know: all you needed was overlays. Just as one can override a package, overlays, with their final + prev, allow user to modify the Nixpkgs graph by extending and/or changing Nixpkgs. I like to think of this as turning Nixpkgs into “Ourpkgs”.

/asset/_hashed/nixtamal/image/ourpkgs-w3hkgfk7q4h1d27kk03fblpqri0wkw8r.jpg

Overlays are built on Nix’s fix point & laziness features, but we won’t get into that here (Nixcademy has a good primer on overlays worth reading for something in depth).

One example might be:

final: prev: {
   h2o = prev.h2o.override {
      openssl = final.openssl_legacy;
   };
   our-pkg = final.callPackage ./our-pkg.nix { };
}

which will override all H2O to use “legacy” OpenSSL to support older browsers for instance. Or extending Nixpkgs to include our-pkg (so we can reference it as pkgs.our-pkg). This is useful to know, but it doesn’t address mixing in other inputs.

Caution!

You can’t always ‘just’ overlay older version if the versions if the build recipes are too different or a newer parckage version can’t compile with your older libraries, but many times it does ‘just work’™. If all you need is a one-off patch from from upstream (such as an in-review-but-not-merged pull request in Nixpkgs), Nixtamal’s patches might be a better tool for that job as it can cover broader topics like NixOS modules, assertions, & other things that either can’t or are too cumbersome to fold in using the overlay method.

Interlude: our Nixtamal workbench

Nixtamal set up

$ nixtamal set-up --nixpkgs-channel nixos-26.05
┏┓╻+╻ ╱┏┳┓┏┓┏┳┓┏┓╻
┃┃┃┃┗━┓╹┃╹┣┫┃┃┃┣┫┃
╹┗┛╹╱ ╹ ╹ ╹╹╹ ╹╹╹┗┛

Fetching fresh value for 「nixpkgs」 …
Prefetching input 「nixpkgs」 … (this may take a while)
Prefetched 「nixpkgs」.
Making manifest file @ version:1.2.0
$ nixtamal tweak

Adding our unstable pin

// ┏┓╻+╻ ╱┏┳┓┏┓┏┳┓┏┓╻
// ┃┃┃┃┗━┓╹┃╹┣┫┃┃┃┣┫┃   Read the manpage:
// ╹┗┛╹╱ ╹ ╹ ╹╹╹ ╹╹╹┗┛  $ man nixtamal-manifest
version "1.2.0"
inputs {
	nixpkgs {
		archive {
			url "{{fresh_value}}/nixexprs.tar.xz"
		}
		hash algorithm=SHA-256
		fresh-cmd {
			$ curl -Ls --http2 --compressed -o "/dev/null" -w "%{url_effective}" "https://channels.nixos.org/nixos-26.05"
		}
	}
	// unstable ↯
	nixpkgs-unstable {
		archive {
			url "{{fresh_value}}/nixexprs.tar.xz"
		}
		hash algorithm=SHA-256
		fresh-cmd {
			$ curl -Ls --http2 --compressed -o "/dev/null" -w "%{url_effective}" "https://channels.nixos.org/nixpkgs-unstable"
		}
	}
}

Lock it up, Mharti

$ nixtamal lock
INPUTS
✓ nixpkgs (Archive)                        Fresh
✓ nixpkgs-unstable (Archive)          Prefetched

Doing an overlay

REPLing around to find out

$ nix repl --file nix/tamal
Nix 2.34.7
Type :? for help.
Loading installable ''...
Added 2 variables.
nixpkgs, nixpkgs-unstable
nix-repl> :p (import nixpkgs { }).h2o.version
2.3.0-rolling-2026-05-15

nix-repl> :p (import nixpkgs-unstable { }).h2o.version
2.3.0-rolling-2026-06-10

These versions make it quite clear we are referencing different versions 😅

Creating a simple release.nix

let
   inputs = import ./nix/tamal { };

   pkgs = import inputs.nixpkgs { };
in
{
   h2o = pkgs.h2o;
}

Check

$ nix repl --file release.nix
nix-repl> :p h2o.version
2.3.0-rolling-2026-05-15

Finale: Referencing that nixpkgs-unstable

let
   inputs = import ./nix/tamal { };

   pkgs-unstable = import inputs.nixpkgs-unstable { };

   pkgs = import inputs.nixpkgs {
      overlays = [
         (final: prev: {
            inherit (pkgs-unstable) h2o;
         })
      ];
   };
in
{
   h2o = pkgs.h2o;
}

Check

$ nix repl --file release.nix
nix-repl> :p h2o.version
2.3.0-rolling-2026-06-10

There we have it: a pkgs with h2o from a diffent Nixpkgs… & it’s still overridable by the next user:

:p (h2o.overrideAttrs (old: { inherit (old) src; version = "🕱"; })).version
🕱

Why you would make your version 🕱 would leave me with a lot of questions, but I’m happy you could do it if you needed.