+ +
+

+ Keys features +

+
    +
  • +

    + Automate the manual work of input pinning for dependency management +

    +
  • +
  • +

    + Allow easy ways to lock & refresh those inputs +

    +
  • +
  • +

    + Declarative KDL manifest file over imperative CLI flags +

    +
  • +
  • +

    + diff/grep-friendly lockfile +

    +
  • +
  • +

    + Host, forge, VCS-agnostic +

    +
  • +
  • +

    + Choose eval time fetchers (builtins) or build time fetchers (Nixpkgs, default) — which opens up fetching now-supported Darcs, Pijul, & Fossil +

    +
  • +
  • +

    + Supports mirrors +

    +
  • +
  • +

    + Override hash algorithm on a per-project & per-input basis — including BLAKE3 support[*] +

    +
  • +
  • +

    + Custom freshness commands +

    +
  • +
  • +

    + No experimental Nix features required +

    +
  • +
+ +
+
+

+ Showcase +

+
+

+ Set up +

+

+      
+
+

+ Tweak the manifest with your $EDITOR +

+
version "1.0.0"
+// By default in this project, use experimental BLAKE3 algorithm for
+// quicker, safer hashing
+default-hash-algorithm BLAKE3
+// Define & even reuse patches
+patches {
+	// Unique name for referencing in manifest inputs
+	chroma-0.22.0 "https://patch-diff.githubusercontent.com/raw/NixOS/nixpkgs/pull/478519.patch" {
+		// Override the project default hash algorithm
+		hash algorithm=SHA-512 expected="1mdsfx204bgia572fydnmjy78dkybbcnjx20qn9l4q65r29ry28c"
+	}
+}
+// Define inputs
+inputs {
+	// Unique name for referencing in Nix
+	nixpkgs {
+		// Fetch an archive with string templating support
+		archive {
+			url "https://github.com/NixOS/nixpkgs/archive/{{fresh_value}}.tar.gz"
+		}
+		hash algorithm=SHA-256
+		// Apply patches to the source now while awaiting review
+		patches chroma-0.22.0
+		// cURL an Atom feed for updates, stat a directory, whatever you
+		// need so long as it returns a string, you can use it!
+		// This also means you can prevent downloading massive files by
+		// deciding yourself what “fresh” means to you.
+		fresh-cmd {
+			$ git ls-remote --branches "https://github.com/NixOS/nixpkgs.git" --refs nixpkgs-unstable
+			| cut -f1
+		}
+	}
+	nixtamal {
+		// Use VCSs not supported by `builtins`
+		darcs {
+			repository "https://darcs.toastal.in.th/nixtamal/stable"
+			// fallback to mirrors when a host is down
+			mirrors "https://smeder.ee/~toastal/nixtamal.darcs"
+		}
+		fresh-cmd {
+			$ curl -sL "https://darcs.toastal.in.th/nixtamal/stable/_darcs/weak_hash"
+		}
+	}
+	// Even static JSON files can be inputs
+	mozilla-tls {
+		file {
+			url "https://ssl-config.mozilla.org/guidelines/{{fresh_value}}.json"
+			mirrors "https://raw.githubusercontent.com/mozilla/ssl-config-generator/refs/tags/v{{fresh_value}}/src/static/guidelines/{{fresh_value}}.json"
+		}
+		// Scrape a webpage for the latest version
+		fresh-cmd {
+			$ curl -sL "https://wiki.mozilla.org/Security/Server_Side_TLS"
+			| htmlq -t "table.wikitable:last-of-type > tbody > tr:nth-child(2) > td:first-child"
+		}
+	}
+	// Download & pin a model from Hugging Face, then can be used like with
+	// `specialArgs = { inherit inputs; }`:
+	//
+	// services.llama-cpp = {
+	//    enable = true;
+	//    model = "${inputs.Qwen2_5-Coder-7B-Instruct}";
+	// }
+	Qwen2_5-Coder-7B-Instruct {
+		file {
+			url "https://huggingface.co/Qwen/Qwen2.5-Coder-7B-Instruct-GGUF/resolve/{{fresh_value}}/qwen2.5-coder-7b-instruct-q5_k_m.gguf"
+		}
+		fresh-cmd {
+			$ curl -fsL "https://huggingface.co/api/models/Qwen/Qwen2.5-Coder-7B-Instruct-GGUF/commits/main?path=qwen2.5-coder-7b-instruct-q5_k_m.gguf"
+			| jq -r ".[0].id"
+		}
+	}
+}
+
+
+

+ Lock or refresh your new inputs +

+

+      
+
+

+ Using in a project +

+
let
+   # Import the inputs attrset from the $NIXTAMAL_DIRECTORY (default:
+   # nix/tamal), which takes a configuration attrset:
+   #
+   # {
+   #    system ? builtins.currentSystem,
+   #    nixpkgs ? null,
+   #    bootstrap-nixpkgs-lock-namee ? null,
+   # }:
+   #
+   # system : string
+   #    The system architecture (useful for pure evaluation)
+   # bootstrap-nixpkgs : derivation
+   #    A Nixpkgs source for bootstrapping. This is useful if using Nixtamal
+   #    from inside another another pinning tool, OR, if you are willing to
+   #    trade off a bit of purity at the fetcher level for better  performance
+   #    / saving data, you can pass { bootstrap-nixpkgs = ≮nixpkgs≯; } from the
+   #    host system as the system’s Nixpkgs fetchers are likely stable enough
+   #    for your bootstrapping needs (& we feature check some of the API).
+   # bootstrap-nixpkgs-lock-name : string
+   #    Key name from inputs to use as the bootstrapping Nixpkgs if you
+   #    want/need inputs.nixpkgs to point to something else.
+   inputs = import ./nix/tamal { };
+
+   pkgs = import inputs.nixpkgs {
+      overlay = [
+         # exposes the “dag-yo” package
+         (import "${inputs.my-cool-package}/nix/overlay")
+      ];
+   };
+in
+pkgs.dag-yo # punted‼
+
+
+
+

+ Comparison +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ Nix pinning tool comparisons +
+

+ Pinning tool +

+
+

+ Nixtamal +

+
+

+ Nix channels +

+
+

+ Nix flakes +

+
+

+ npins +

+
+

+ niv +

+
+

+ Yae +

+
+ Same state per machine + + yes + + only if manually pinning + + yes + + yes + + yes + + yes +
+ Per-project support + + yes + + no + + yes + + yes + + yes + + yes +
+ Versioned schemas + + yes + + – + + no + + yes + + yes + + no +
+ Requires experimental Nix features + + no + + no + + yes + + no + + no + + no +
+ Splits lockfile vs. manifest duties + + yes (manifest.kdl) + + no + + yes (flake.nix) + + no + + no + + no +
+ Requires Nixpkgs + + used for bootstrapping & some features require it, but possible with fetch-time=eval + + no + + no + + no + + no + + no +
+ Fetch CVS + + no[2] + + no + + no + + no + + no + + no +
+ Fetch Darcs + + yes + + no + + no + + no + + no + + no +
+ Fetch Fossil + + yes + + no + + no + + no + + no + + no +
+ Fetch Git + + yes + + no + + yes + + yes + + yes + + yes +
+ Fetch GNU Bazaar + + no[1] + + no + + no + + no + + no + + no +
+ Fetch Mercurial + + no[2] + + no + + yes + + no + + no + + no +
+ Fetch Pijul + + yes + + no + + no + + no + + no + + no +
+ Fetch Subversion + + no[2] + + no + + no + + no + + no + + no +
+ Fetch torrent + + no[1] + + no + + no + + no + + no + + no +
+ Fetch URLs + + yes + + yes + + yes + + yes + + yes + + yes +
+ User-written freshness logic + + fresh-cmd + + no + + no + + no + + no + + no +
+ Version constraints + + Gate with fresh-cmd or Jingoo templating (DIY) + + no + + no + + Semver on some input kinds + + no + + Git tag predicate +
+ Configure hash algorithm + + yes, per-project + per-input & BLAKE3 support + + no + + no + + no + + no + + no +
+ Mirror support + + yes, on supported kinds + + no + + no + + no + + no + + no +
+ Patch support + + yes, declarative + + no + + must apply manually or pull in a dependency to handle + + must apply manually + + must apply manually + + must apply manually +
+ Forge-specific URL schemes or semantics + + no + + no + + yes + + yes + + yes, & defaults to proprietary MS GitHub + + no +
+ Freeze inputs for convenience + + yes + + no + + no + + yes + + no + + no +
+ Bin license + + GPL-3.0-or-later + + LGPL-2.1-or-later + + LGPL-2.1-or-later + + EUPL-1.2 + + MIT + + GPL-3.0 +
+ Main implementation language + + OCaml + + C++ + + C++ + + Rust + + Haskell + + Go +
+ Manifest file format + + KDL + + – + + Nix (special constraints) + + – + + – + + – +
+ Lockfile file format + + JSON + + – + + JSON + + JSON + + JSON + + JSON +
+
+ +
+
+

+ Design constraints +

+
    +
  • +

    + All inputs are named and listed up front +

    +
  • +
  • +

    + Inputs are written declaratively in a manifest file +

    +
  • +
  • +

    + Lockfiles are machine-written, not hand-edited configuration +

    +
  • +
  • +

    + VCSs not in the builtins must be supported +

    +
  • +
  • +

    + No forge-specific rules +

    +
  • +
  • +

    + Users define how freshness is checked +

    +
  • +
+
+
+

+ Technical choices +

+
    +
  • +

    + After bootstrapping with Nixpkgs, use its fetchers as builtins fetchers are (by design) feature-poor +

    +
  • +
  • +

    + Uses nix-prefetch-scripts from Nixpkgs input value fetching +

    +
  • +
  • +

    + Allows side-by-side use with other pinning tools during transition +

    +
  • +
  • +

    + Nixtamal is dog-fooded on itself +

    +
  • +
+
+
+

+ Ready to try & install? +

+

+ Install Nixtamal now! +

+ + Note +

+ Official repositories should be at toastal.in.th domains if unsure +

+
+
+