# nix-update: bumping a Nix package version and every hash that follows it

> nix-update edits a Nix expression to a newer upstream version and then fixes the source hashes, dependency hashes, lockfiles and vendored dependencies that the bump breaks, for Rust, Go, npm, pnpm, PHP, Maven, Elixir, Yarn, Zig and .NET packages. It is designed for nixpkgs but works on other package sets, and it can build the result, run its tests and hand the diff to nixpkgs-review.

**Mic92/nix-update** — Swiss-knife for updating nix packages.

- Repository: https://github.com/Mic92/nix-update
- Stars: 892 · Forks: 111
- Language: Python
- License: MIT
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/mic92-nix-update

## Getting it without installing it

nix-update is included in nixpkgs, so there are four ways to run it and they cover every level of commitment. To try it without installing anything, use a nix shell:

```console
$ nix-shell -p nix-update
```

To install it into your profile from your nixpkgs checkout:

```console
$ nix-env -f '<nixpkgs>' -iA nix-update
```

To run it from a git checkout of the project itself:

```console
$ nix-build
$ ./result/bin/nix-update
```

And with flakes enabled:

```console
$ nix run github:Mic92/nix-update
```

That last form is the most convenient for a one-off, and the nix-build one is the most predictable for a contribution workflow. The project is a Python package named nix-update with a single console script, nix-update, pointing at the main function of the nix_update module, and the wheel is built with hatchling from the nix_update package directory. The licence is MIT, the version is 1.16.0, and the last push was on 2026-10-18.

## A version bump is the easy part, the hashes are the work

The command line is a single attribute and an optional version. Change to the directory holding the Nix expression, which could be a nixpkgs checkout or your own repository, and run:

```console
$ nix-update attribute [--version version]
```

With no version given, the tool fetches the latest release for the package, and it can be told to do less or something slightly different. A manual version:

```console
$ nix-update --version=2.1.1 nixpkgs-review
```

The literal word branch asks for the latest commit of the default branch, which is how unstable packages are tracked, and branch=develop asks for a specific branch:

```console
$ nix-update --version=branch=develop nixpkgs-review
```

And the literal word skip updates the source hashes without touching the version at all, which is what you want after a dependency changes underneath you:

```console
$ nix-update --version=skip nixpkgs-review
```

That last one is the mode that shows what the tool is actually for. Changing a version in a Nix expression is a one-line edit; everything that pins the source, the vendored dependencies and the hashes has to be recomputed, and that is where a human spends the time.

## It knows the hash format of a dozen ecosystems

The feature table is the substance of the project, and it is organised by the build system of the package being updated. For Rust it handles buildRustPackage's cargoHash, cargoSha256 and cargoLock, and cargoSetupHook's cargoDeps. For Go it handles buildGoModule's vendorHash and vendorSha256. For npm it handles buildNpmPackage's npmDepsHash and npmConfigHook's npmDeps, and for pnpm the pnpm.fetchDeps pnpmDeps. PHP gets buildComposerProject's vendorHash, Maven gets buildMavenPackage's mvnHash, and Elixir gets mixRelease's mixFodDeps. Yarn is handled through fetchYarnDeps, with a separate line for Yarn Berry covering fetchYarnBerryDeps and its missingHashes file. Zig uses the zigDeps output hash and .NET uses nugetDeps. Each of these is a different way of expressing the same idea, a hash of inputs that must change when the version changes, and knowing which one applies to a given package is the knowledge the tool encodes.

## Finding the file to patch, and overriding it when it guesses wrong

By default, nix-update locates the file that needs patching using the src attribute of the derivation, and the documentation is candid that this heuristic is wrong in some cases. When it is, there is a flag to point at the right file:

```console
$ nix-update hello --override-filename pkgs/applications/misc/hello/default.nix
```

The same override solves the case of a package that fetches from a release URL the tool does not recognise but still has release information in a repository it can read. The example given is the Signal Desktop package in Nixpkgs, which fetches updates from an updates site but also publishes release information on its GitHub page, so the --url parameter directs the tool at the right repository:

```console
nix-update --url https://github.com/signalapp/Signal-Desktop --override-filename pkgs/applications/networking/instant-messengers/signal-desktop/default.nix   signal-desktop
```

The tool also supports a version regex for extracting version numbers from strings with prefixes or suffixes, which is common in release tags:

```console
$ nix-update jq --version-regex 'jq-(.*)'
```

For packages defined in a flake, the --flake flag is used instead, and nix-update then tries to update either the packages.{currentSystem}.{attribute} or the {attribute} output attribute of the flake. A package in legacyPackages needs the full path including the platform.

## It can go as far as building and testing the result

The tool is not only a text editor for expressions, because a version bump that produces a non-building package is not much use. The feature table has rows for building and running the resulting package, seen through the --build, --run and --shell flags, and a row for running the package tests, through --test. There is a row for committing the updated files, through --commit, and one for running update scripts, the passthru.updateScript convention in Nixpkgs, through --use-update-script. The review step is the one most people will care about, and it is --review, which hands the change to nixpkgs-review. There is also --format, which formats the changed expression, and --system, which specifies the system to use. The last of these matters in practice: a hash computed on one platform can differ from one computed on another, and building on the wrong system produces a patch that fails review rather than one that passes.

## The version detection covers a dozen hosting services

Finding the latest version is the part that has to cope with the whole packaging ecosystem, and the list of supported sources is long: BitBucket, Codeberg, crates.io, Gitea, GitHub, GitLab, npm, PyPi, Radicle, RubyGems.org, Sourcehut and Savannah. A separate row covers custom dependency hashes through the --custom-dep flag, for the package whose dependency hash is not one of the known build systems. And two rows handle the lockfile problem, which is a real part of a version bump for a modern package: generating lockfiles such as Cargo.lock and package-lock.json, through --generate-lockfile and --lockfile-metadata-path, and updating flake outputs through --flake. The design goal, stated in the project's own description, is to work with nixpkgs but also other package sets, which is what makes it useful for a private package repository rather than only for the big one.

## Ruff with everything selected, and mypy with no untyped defs

The project configuration tells you how seriously the author takes the code. The ruff configuration selects ALL rules, which is an unusual choice, and then ignores a specific list, each with the reason written next to it: the copyright rule, the pydocstyle family, todo comments, fixmes, a rule about f-strings in logging, and three rules about subprocess calls and URL opening, with the reasons given as the code being careful about untrusted input. It also ignores the trailing comma rule that conflicts with the formatter, the rule that finds commented-out code, the line length rule because the formatter handles it, and the print rule, since this is a command line tool whose output is the point. Mypy is configured with Python 3.11, redundant casts warned, untyped calls and untyped definitions disallowed, implicit optional disallowed, and the package list set to the nix_update package alone. Tests are allowed to use assert, and pytest runs with verbose output and the xdist plugin for parallel execution. The treefmt.nix file at the root suggests formatting is handled by the same Nix toolchain that builds the package.

## Conclusion

nix-update suits a maintainer of a Nix package set who bumps a version weekly and does not want to chase hash errors by hand, since the hash repair per ecosystem is the whole point of the tool. It does not suit a package whose release information lives somewhere the tool cannot read, unless you point it at the right URL with --url, and the file location heuristic needs overriding in some cases. Before you run it on a package you care about, check the file it decides to patch, since the src attribute heuristic is documented as sometimes wrong, and use --version=skip when you only want the hashes refreshed.

## FAQ

### How do I install nix-update?

It is included in nixpkgs, so you can use nix-shell -p nix-update to run it without installing, nix-env -f '<nixpkgs>' -iA nix-update to install it, nix-build and ./result/bin/nix-update to run it from a git checkout, or nix run github:Mic92/nix-update with flakes enabled.

### How do I update only the hashes without changing the version?

Pass the literal word skip as the version, for example nix-update --version=skip nixpkgs-review. The literal word branch does the opposite, fetching the latest commit of the default branch, and branch=develop targets a named branch.

### Which build systems does nix-update know how to fix hashes for?

Rust through buildRustPackage and cargoSetupHook, Go through buildGoModule, npm through buildNpmPackage and npmConfigHook, pnpm through pnpm.fetchDeps, PHP through buildComposerProject, Maven through buildMavenPackage, Elixir through mixRelease, Yarn and Yarn Berry through fetchYarnDeps and fetchYarnBerryDeps, Zig through zigDeps, .NET through nugetDeps, and anything else through the --custom-dep flag.

### What if nix-update picks the wrong file or the wrong release source?

The file is located from the src attribute of the derivation, which the documentation says is wrong in some cases, and --override-filename points at the right file. For a package with a non-standard release URL, --url directs the tool at a repository that does have release information, with the Signal Desktop package in Nixpkgs given as the example.

## Sources

- [Issues](https://github.com/Mic92/nix-update/issues)
- [License: MIT](https://github.com/Mic92/nix-update/blob/main/LICENSE)
- [Mic92/nix-update on GitHub](https://github.com/Mic92/nix-update)
- [README](https://github.com/Mic92/nix-update/blob/main/README.md)
- [Releases](https://github.com/Mic92/nix-update/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/mic92-nix-update
