Open-source project
nix-community/nurl avatar
nix-community/nurl

nurl generates Nix fetcher calls from a repository URL

Generate Nix fetcher calls from URLs [maintainer=@figsoda]

800 stars11 forksRustMPL-2.0

At a glance

What is it?
nurl is a small Rust CLI that turns a source URL and revision into a ready to paste Nix fetch expression, with the hash filled in. It covers GitHub, GitLab, Gitea, crates.io, PyPI, Hex and plain archives, and it is aimed at packagers who are tired of hand-writing fetchers.
Who is it for?
nurl fits packagers who already know Nix and want a fetcher expression with a correct hash in one command, and it is a poor fit for anyone who wants a complete package definition or needs results checked against a source they control. Verify the fetcher choice with nurl --list-possible-fetchers on your exact URL, confirm that the printed hash matches the archive you expect, and remember that the overwrites nurl accepts are not validated for you.
Can I use it commercially?
Yes, with conditions. MPL-2.0 is a weak copyleft licence: you can use it inside commercial and closed-source software, but if you distribute changes to its own files, you must publish those changes under the same licence.
Is it still maintained?
Yes. The repository last received commits 2 days ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The problem nurl solves: fetcher boilerplate in every package

Every Nix package that pulls in upstream source starts with a fetcher expression and a hash. The expression names a function such as fetchFromGitHub or fetchurl and fills in arguments like owner, repo, tag and hash. Writing that by hand works, until the source moves to another host, the release is a tarball instead of a git tag, or the archive layout changes and the hash has to be recomputed. The hash is the awkward part, because it has to match the exact bytes Nix will fetch.

nurl removes that typing. Give it a URL and, optionally, a revision, and it decides which fetcher fits, fetches the source, computes the hash and prints the expression. The README frames this as generating Nix fetcher calls from repository URLs, and the crate description says the same thing in fewer words. The target audience is narrow and clear: people writing or updating Nix expressions who already understand what a fixed output derivation is.

It is not a package generator. The README points readers who want complete packages to nix-init, which builds on top of nurl and adds features to reduce boilerplate. That division of labour tells you what nurl is: one narrow, well defined step in a larger workflow.

How inference works and which fetchers exist

The core mechanism is URL shape to fetcher mapping. nurl parses the URL with the gix-url crate, which normalises Git style references, and then matches the host and path pattern against the known fetchers. The README lists eighteen of them: builtins.fetchGit, fetchCrate, fetchFromBitbucket, fetchFromGitHub, fetchFromGitLab, fetchFromGitea, fetchFromGitiles, fetchFromRepoOrCz, fetchFromSourcehut, fetchHex, fetchPypi, fetchgit, fetchhg, fetchpatch, fetchpatch2, fetchsvn, fetchurl and fetchzip.

That list explains the tool's reach and its edges at once. Registry and forge hosts get dedicated fetchers with named arguments, while Mercurial, Subversion, patch files and bare archives fall back on the generic Nix builtins.

Hash computation happens over HTTP. The Cargo manifest shows a dependency on ureq with its json feature, which is how nurl talks to GitHub, GitLab and forge APIs for tag and revision metadata, and how it downloads archives for hashing.

toml
[dependencies]
ureq = { version = "3.4.0", features = ["json"] }
gix-url = "0.37.0"

Two flags let you inspect the mapping without committing to it. Listing every fetcher and listing only the ones that can be produced from a URL alone are separate commands:

bash
  -l, --list-fetchers
          List all available fetchers

The distinction matters because a fetcher you can name is not the same as a fetcher nurl can infer. Asking for the second list tells you whether inference will work for the URL in front of you, before a single byte is fetched.

A first run: from GitHub tag to pasted expression

The README shows the whole interaction in one example. nurl takes a URL and a revision, and prints the expression with the hash already computed. The 2>/dev/null in the example only hides the download progress output that nurl writes while it works.

bash
$ nurl https://github.com/nix-community/patsh v0.2.0 2>/dev/null
fetchFromGitHub {
  owner = "nix-community";
  repo = "patsh";
  tag = "v0.2.0";
  hash = "sha256-7HXJspebluQeejKYmVA7sy/F3dtU1gc4eAbKiPexMMA=";
}

Note that the revision is optional and the fetcher is inferred. When nurl cannot recognise the host, you can name the fetcher yourself:

bash
  -f, --fetcher <FETCHER>
          Specify the fetcher function instead of inferring from the URL

And when the host is one nurl does not know but the source is still a git repository, the fallback fetcher takes over. Its default is fetchgit, which is the conservative choice for an unknown URL:

bash
  -F, --fallback <FALLBACK>
          The fetcher to fall back to when nurl fails to infer it from the URL

If all you want is the hash itself, for example to paste into a file that already has the expression, the hash flag strips everything else:

bash
  -H, --hash
          Only output the hash

Overwriting arguments and the quiet gap in --parse

A generated expression rarely matches a package file exactly. nurl handles that with two separate mechanisms. --arg passes extra arguments to the fetcher, so they take part in the hash computation. --overwrite changes the final printed output only, and the help text is explicit that overwrites are ignored when the hash is fetched:

bash
  -o, --overwrite <NAME> <EXPR>
          Overwrite arguments in the final output, not taken into consideration when
          fetching the hash

The help carries a warning with it: nurl does not verify any of the overwrites, so for the output to stay valid the user should not overwrite anything that would change the hash. In practice that means renaming arguments and rewriting version strings, not swapping a tag for a different revision.

There is a revision-specific shortcut for the most common rewrite, a version placeholder in front of a tag:

bash
      --overwrite-rev <EXPR>
          Same as --overwrite (rev|tag|version) <EXPR>, depending on the rev-like
          attribute the fetcher uses

A second gap is worth knowing before you script around nurl. The parse mode inspects a URL and reports what nurl would do without downloading anything, which is useful for a quick check. The help text notes, however, that the argument and overwrite options are ignored silently in that mode:

bash
  -p, --parse
          Parse the url without fetching the hash, output in json format

          Note that --arg(-str) and --overwrite(-str) will be ignored silently

Silently is the operative word. A script that passes an overwrite and expects the parsed output to reflect it will not see an error, only a different result than it wanted.

Where nurl is the wrong tool

Three limits show up in practice. First, nurl emits a fetcher call, not a package. If you need pname, version, meta attributes, build inputs or a license field, you are writing the package yourself, and the README directs you to nix-init for that layer.

Second, inference only covers hosts nurl recognises. A self hosted forge at an unusual domain, an internal artifact server or a mirror with a nonstandard path will need --fetcher, and if the pattern is not a git repository at all, the fallback of fetchgit will not help either.

Third, nurl depends on network services to do its work. Tag metadata comes from forge APIs and hashes come from downloading archives, so a rate limited or offline forge means the tool fails at exactly the point where you needed the hash most. The help offers no offline mode for that case, though there is an expression mode for a different purpose: computing the hash of a fixed output derivation that already exists in nixpkgs, which implies --hash and ignores other options.

A fourth point is about trust. The printed hash is computed from whatever the network returned at that moment. Nothing in the documented behaviour checks that the archive you hashed is the archive you intended, and the overwrite mechanism is explicitly unverified. For a hash you did not compute yourself, review the output before it enters a package set.

nurl against nix-prefetch

The README includes a direct comparison with nix-prefetch, and the differences are about where the work happens.

nurl infers the fetcher from the URL. nix-prefetch needs you to pick the fetcher and supply the arguments by hand. That is the core trade: nurl removes typing, nix-prefetch keeps the choice in your hands.

nix-prefetch relies on fixed output derivations, which the README calls slow, while nurl tries alternatives when possible. nix-prefetch is the more configurable of the two and supports file attributes. Its interface resembles nix-build, which matters for people already used to that syntax. nurl keeps some features aimed at generated packages, among them the indent option for nesting output inside a larger expression and the list-possible-fetchers command.

The choice follows from where you sit in the packaging workflow. If you are exploring what hash a given URL produces, or you want the expression with the right arguments filled in, nurl does the work for you. If you need per file attributes, unusual fetcher behaviour or fine control over how the derivation is built, nix-prefetch exposes that and nurl does not.

Maintenance, packaging and the licence

The last push to the repository was on 2026-10-19, and the release history shows recent activity: v0.4.1 on 2026-08-29, after v0.4.0 on 2026-02-06. Before those, v0.3.13 was published on 2023-07-21, so the gap between the older and newer releases is long, while the current pace of releases is regular. The manifest identifies the maintainer as figsoda and pins the crate to edition 2024.

The project is a single Rust crate with a Cargo.lock, a flake.nix for Nix users, and a build script. The build dependencies include clap_complete and clap_mangen, which is how shell completions and man pages get generated from the same clap definition that powers the command line interface. That means the documented options in the README are the real options, not a hand maintained list that can drift.

The licence is MPL-2.0, a file level copyleft scheme. Its practical implication for a packager is that MPL covered files stay covered if you modify them, while a larger work that merely includes nurl is not forced into the same terms. This is a licensing note rather than legal advice, and it is the same licence nix-init uses, which keeps the two tools compatible in the same repository.

Editorial conclusion

nurl fits packagers who already know Nix and want a fetcher expression with a correct hash in one command, and it is a poor fit for anyone who wants a complete package definition or needs results checked against a source they control. Verify the fetcher choice with nurl --list-possible-fetchers on your exact URL, confirm that the printed hash matches the archive you expect, and remember that the overwrites nurl accepts are not validated for you.

Frequently asked questions

How do I install nurl?

The README does not give install commands. It links to the crate page on crates.io and the repository contains a flake.nix, so both the crates.io distribution and the Nix flake are available; the README points to nix-init for the fuller packaging workflow.

Which Nix fetchers can nurl generate for a URL?

The README lists eighteen fetchers, from fetchFromGitHub, fetchFromGitLab, fetchFromGitea and fetchFromSourcehut through fetchCrate, fetchPypi and fetchHex to the generic fetchgit, fetchhg, fetchsvn, fetchurl and fetchzip. The --list-possible-fetchers command prints the subset nurl can infer without an explicit --fetcher.

What is the difference between --arg and --overwrite in nurl?

The --arg value is passed to the fetcher and is taken into account when the hash is computed, while --overwrite only changes the printed output and is ignored for hashing. The help also states that nurl does not verify overwrites, so anything that would change the hash must not be overwritten.

Does nurl work without downloading the source?

The --parse mode inspects a URL and outputs json without fetching the hash. The help notes that --arg and --overwrite are ignored silently in that mode, so parsed output does not reflect overwrites.

Official sources

  1. License: MPL-2.0
  2. nix-community/nurl on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/nix-community-nurl.svg)](https://hysenlabs.com/projects/nix-community-nurl)

Was this useful?