✔️ Table of Contents
Packaging a Rust crate for Nixpkgs
NOTE: This example assumes you’re packaging a crate that’s already on crates.io, or you’re packaging an existing Rust project for nixpkgs.
Nixpkgs is a big repository, so it helps to start with a focused workflow:
create a branch, add a package under pkgs/by-name/, build it, then open a PR.
Clone nixpkgs
- Fork and clone
NixOS/nixpkgs:
git clone git@github.com:your-user/nixpkgs.git
cd nixpkgs
git remote add upstream git@github.com:NixOS/nixpkgs.git
(SSH avoids HTTPS helper issues)
- If your clone is shallow, convert it to full history (doesn’t lose work):
git fetch --unshallow --tags
Create a branch and add package:
- Create a branch before changes preferably:
git switch -c mdbook-rss-feed
Add the package under pkgs/by-name
New top-level packages should generally go under
pkgs/by-name/<2 letters>/<name>/package.nix (e.g.
pkgs/by-name/md/mdbook-rss-feed/package.nix). Packages in pkgs/by-name are
picked up automatically and usually don’t require edits to all-packages.nix.
Write package.nix (Rust crate example)
Start with rustPlatform.buildRustPackage and fetchCrate:
{
lib,
rustPlatform,
fetchCrate,
versionCheckHook,
}:
rustPlatform.buildRustPackage rec {
pname = "mdbook-rss-feed";
version = "1.3.0";
src = fetchCrate {
inherit pname version;
hash = "output of `nix hash convert` shown below";
};
cargoHash = lib.fakeHash;
nativeInstallCheckInuts = [
versionCheckHook
];
doInstallCheck = true;
meta = {
description = "mdBook preprocessor that generates RSS, Atom, and JSON feeds";
mainProgram = "mdbook-rss-feed";
homePage = "https://crates.io/crates/mdbook-rss-feed";
license = lib.licenses.asl20;
maintainers = [ lib.maintainers.sayls88 ];
};
}
Prefetch the crate hash:
Use fetchCrate / crate2nix style workflow, or just prefetch the crates.io
tarball:
nix-prefetch-url \
--unpack \
https://crates.io/api/v1/crates/mdbook-rss-feed/1.3.0/download
That prints a base32 hash: 0932843lknasdlfkm2lkdnflaknldvdsvser
Convert it to sri format:
nix hash convert --hash-algo sha256 --from nix32 --to sri 0932843lknasdlfkm2lkdnflaknldvdsvser
The above commands output looks like: sha256-...=
Put the resulting sha256-... into src.hash:
src = fetchCrate {
inherit pname version;
hash = "sha256-...";
};
Get cargoHash via a failing build
In the nixpkgs root (i.e., the nixpkgs directory), run:
nix-build -A mdbook-rss-feed
# OR nix3 format
nix build .#mdbook-rss-feed
Nix will fail with a message like:
hash mismatch
specified: sha256-....
got: sha256-1...
Copy the got value into cargoHash, rebuild, and it should succeed.
Sanity check: from nixpkgs root :
./result/bin/mdbook-rss-feed --version
Adding yourself as maintainer
Edit nixpkgs/maintainers/maintainer-list.nix add your user in alphabetical
order:
your-handle = {
email = "you@example.com";
name = "Your Name";
github = "your-gh-handle";
githubId = 12345678;
};
If you specify github, nixpkgs expects githubId too. You can get it from:
https://api.github.com/users/<user>.
The nixpkgs maintainers prefer if you add the maintainer-list.nix as a
separate commit.
git commit -m "maintainers: add <user>"
Treefmt
Run treefmt the nixpkgs way, from the repo root. Run this right before you push, my editors formatter does something different with single entry lists than what Nixpkgs wants:
nix develop --command treefmt
nix fmt
Rebase and push safely
From the mdbook-rss-feed branch:
git fetch upstream --tags
git rebase upstream/master
Commit and push your PR branch:
Then commit and push
git commit -m "mdbook-rss-feed: init at 1.3.0"
# First push
git push origin mdbook-rss-feed
# Use `--force-with-lease` only if you rebased/amended and need to rewrite the PR branch.
# git push --force-with-lease origin mdbook-rss-feed
--force-with-lease is the recommended safe force-push for PR branches.
If --force-with-lease says “stale info”, fetch the remote branch ref first,
then retry.
Then commit and push
git commit -m "mdbook-rss-feed: init at 1.3.0"
git push -u origin mdbook-rss-feed
Then:
-
Go to GitHub -> your fork
-
Click “Compare & pull request” on the
mdbook-rss-feedbranch -
Fill out the PR template (why useful, tested on x86_64-linux, etc.)
-
Submit!
The package will go through CI checks, and once green + approved by a maintainer, it’ll land in nixpkgs.
Recovering from Mistakes
You’re bound to make mistakes, if you learn some Git basics it will help you quite a bit.
You should avoid adding new commits for small fixes like typos, formatting, or minor adjustments requested in review. For substantial changes that add functionality, a new commit may be more appropriate.
Say that we pushed our PR and one of the maintainers gave us a suggested change, (they want us to follow conventions and remove a trailing period from our packages description for this example).
-
Make the edit locally (remove the trailing period in the file)
-
Stage the change:
git add pkgs/by-name/xx/your-package/package.nix(avoidgit add -Aas it stages everything, which can accidentally include unrelated files) -
Amend the commit:
git commit --amend --no-edit(this preserves your original commit message, if you want to change the commit message usegit commit --amend) -
Force push:
git push --force-with-lease(This is safer than just using--forcebecause it will fail if someone else has pushed commits to your branch that you don’t have locally)
Alternative for Multiple Commits
Interactive rebase is useful when your PR has several “WIP” commits (or you added a small review fix as a separate commit) and you want to present a cleaner history before merge.
You can use interactive rebase to squash all your would be small fix commits into a single commit they belong to.
Avoid squashing if the commits represent distinct, reviewable changes that stand on their own.
Basic Workflow (squash/fixup)
- Decide how many commits back you want to edit (example: last 3 commits):
git rebase -i HEAD~3
- Your editor opens with a “todo” list (oldest at top). Change later commits
from
picktofixuporsquash:
-
fixup= combine into the previous commit, discard this commit message. -
squash= combine, but keep/edit commit messages.
Example todo:
pick 1111111 mdbook-rss-feed: init at 0.1.0
pick 2222222 mdbook-rss-feed: fix trailing period
pick 3333333 mdbook-rss-feed: formatting
Change to:
pick 1111111 mdbook-rss-feed: init at 0.1.0
fixup 2222222 mdbook-rss-feed: fix trailing period
fixup 3333333 mdbook-rss-feed: formatting
- Save/close: if you squashed, Git will prompt you to edit the final combined message.
Push updated history
You have to force-push because rebase rewrites commit SHAs:
git push --force-with-lease
# If something goes wrong
# git rebase --abort
# If you hit conflicts, fix the files, then:
# git add <files>
# git rebase --continue
If you have an unrelated change accidentally included (for example: you staged an extra file), it’s usually better to fix it via rebase/splitting before reviewers spend time re-reviewing noise.
As of 01-13-26 I have been waiting for 2 weeks for the darwin checks to complete, I guess this bottleneck has gotten worse. I guess most PRs take about 6 weeks to resolve FYI.