Keys features
-
Automate the manual work of input pinning, allowing to lock & refresh inputs
-
Declaritive KDL manifest file over imperative CLI flags
-
Host, forge, VCS-agnostic
-
Fetchers from Nixpkgs not supported by the builtins (currently Darcs, Pijul)
-
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
$ nixtamal set-up Fetching fresh value for 「nixpkgs」 … Prefetching input 「nixpkgs」 … (this may take a while) Prefetched 「nixpkgs」. Making manifest file @ version:0.4.0 $ nixtamal tweak
Tweak the manifest with your $EDITOR
version "0.4.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" } } mozilla-tls { // Even static JSON files can be inputs 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" } } }
Lock or refresh your new inputs
$ nixtamal lock … $ nixtamal refresh …
Comparison
|
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 | no | no | no | no | no |
| Fetch CVS | no[2] | no | no | no | no | no |
| Fetch Darcs | yes | no | no | no | no | no |
| Fetch Fossil | no (planned, awaiting prefetcher) | 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 |
No prefetcher exists
Bare-bones prefetchers:
While these could be supported like fetchurl does, VCSs can & should provide structured output (currently supported prefetchers all output 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