# niv for pinned dependencies in Nix projects

> niv is a command-line dependency manager for Nix projects, including projects that do not use flakes. It records remote sources in nix/sources.json, generates nix/sources.nix, and supports adding, updating, showing, modifying, and dropping dependencies.

**nmattia/niv** — Easy dependency management for Nix projects

- Repository: https://github.com/nmattia/niv
- Website: https://github.com/nmattia/niv
- Stars: 1,869 · Forks: 75
- Language: Haskell
- License: MIT
- Published: 2026-10-16 · Updated: 2026-10-16 · Language: en
- Canonical page: https://hysenlabs.com/projects/nmattia-niv

## What niv solves in a Nix project

niv addresses the part of dependency management that appears when a Nix project needs source code, archives, or other remote inputs that are not declared entirely inside the local Nix expressions. The README says it can track and pin any external dependency in a Nix project, whether or not the project uses Nix flakes. This makes it useful for repositories that already use Nix for builds but need a straightforward way to retain a known revision of an external package.

The main design choice is a single project file, `nix/sources.json`. That file stores the metadata niv needs to fetch and update sources. The generated `nix/sources.nix` exposes those sources as a Nix object, allowing expressions to import them by name. The repository describes `init` as bootstrapping a Nix project, creating both files and initializing `sources.json` with `niv` and `nixpkgs`.

niv is therefore aimed at authors who want explicit dependency records that can be inspected and version-controlled. The README does not claim that niv replaces Nix itself or provides a package index. It manages the source entries used by a project. That distinction matters for teams deciding between niv and a native flakes workflow: niv offers a smaller, file-centered mechanism, while flakes are a separate Nix dependency and source-management system.

## How niv represents and fetches sources

The documented data flow starts with `nix/sources.json`. A source entry can include fields such as `owner`, `repo`, `branch`, `rev`, `url`, `url_template`, `sha256`, `description`, and `homepage`. For GitHub repositories, niv can infer this information when possible. The resulting URL points to an archive for a specific revision, while the metadata records the branch and the revision used to produce that URL.

For a GitHub dependency, the README shows an entry for `stedolan/jq` with a revision-specific archive URL, a branch named `master`, a URL template, and a `sha256` value. This indicates that the source record combines human-readable source metadata with values required for fetching. The revision pin is the important part for reproducibility. Updating a package changes the recorded revision and related fields rather than relying on a floating branch at build time.

Custom URLs are also supported. The `add` command accepts a version with `-v` and a reusable URL template with `-t`. The README uses GHC as the example, with a template containing `<version>`, then changes the tracked version with `niv update ghc -v 8.6.2`. The exact type is guessed from the URL template unless `-T` is supplied. The README does not document the complete set of fetch backends or the internal update algorithm, so those details should not be inferred.

GitHub access has several documented controls. `GITHUB_TOKEN` or `NIV_GITHUB_TOKEN` supplies API authentication. The host, API host, API port, insecure mode, and base path can be changed with the listed environment variables.

## Install niv and bootstrap a project

The documented installation path uses nixpkgs. Install the `niv` attribute in an environment managed by `nix-env`:

```bash
$ nix-env -iA nixpkgs.niv
```

The README also gives a development-version command. It runs the command from the GitHub repository, supplies the project cache configuration, and passes `--help` to the program:

```bash
$ nix run github:nmattia/niv#niv \
    --substituters https://niv.cachix.org --trusted-public-keys niv.cachix.org-1:X32PCg2e/zAm3/uD1ScqW2z/K0LtDyNV7RdaxIuLgQM= \
    -- --help
```

After installation, initialize the project. The README expects a `nix` directory containing `sources.json` and `sources.nix`:

```bash
$ niv init
$ tree
.
└── nix
    ├── sources.json
    └── sources.nix
```

The initialized JSON file is based on `data/nixpkgs.json` and tracks the `nixos-unstable` branch of nixpkgs. A Nix expression can then import `sources.nix` and select the `nixpkgs` entry. The README’s example is:

```nix
{ sources ? import ./sources.nix }:
import sources.nixpkgs
  { overlays = [] ; config = {}; }
```

This creates a concrete first use, but the README does not specify every path assumption or provide a complete build command for that generated expression. The visible expectation is that the files exist in the project and that the Nix expression resolves the imported source.

## Add, update, inspect, and drop niv entries

The command set is centered on editing one source file. `add` inserts a package, `update` updates one or all entries, and `drop` deletes an entry. `show` displays package information, while `modify` changes attributes without performing an update. That last distinction is useful when a maintainer wants to change metadata such as a branch or version without causing the command to fetch a newer revision.

For a GitHub repository, the shortest documented workflow is:

```bash
$ niv add stedolan/jq
```

niv infers the repository information when possible. The README says this works especially well for GitHub repositories, which is a narrower claim than universal package discovery. For a custom archive, the command can include both a version and a URL template:

```bash
$ niv add ghc   \
    -v 8.4.3    \
    -t 'https://downloads.haskell.org/~ghc/<version>/ghc-<version>-i386-deb8-linux.tar.xz'
```

To refresh a tracked nixpkgs branch, the documented command is:

```bash
$ niv update nixpkgs
```

A branch can be changed while updating:

```bash
$ niv update nixpkgs -b master
```

For the custom GHC entry, the README shows:

```bash
$ niv update ghc -v 8.6.2
```

The README’s command listing identifies version `0.3.0`, but the repository has no GitHub releases listed. It also exposes `-s` or `--sources-file FILE`, which allows a different source file instead of the default `nix/sources.json`, and `--no-colors` for output without colors. The excerpt of the full command reference is incomplete, so additional command behavior should be checked against the repository’s README or command help before automation depends on it.

## niv’s boundaries compared with Nix flakes

The README explicitly presents niv as “a simple, practical alternative to Nix flakes.” The actual difference is architectural. niv concentrates source metadata in `nix/sources.json` and exposes it through `nix/sources.nix`, with explicit commands for adding and updating entries. It does not present a flake-based project structure in the documented workflow.

That design can be a good fit for an existing project that wants pinning without adopting flakes. It also gives reviewers a visible JSON change when a source revision changes. However, niv’s GitHub convenience depends on GitHub metadata inference and GitHub API access. The README says inference works well for GitHub repositories, but it does not claim equivalent inference for every host or every archive format. A custom URL can still be represented when the maintainer supplies a suitable template.

There is also a revision versus branch distinction. The source record stores a branch and a revision, while the URL is revision-specific. `niv update nixpkgs` moves the entry to the last commit of the configured branch, and `-b master` changes the branch. This is useful for controlled updates, but it means an update is an intentional repository change rather than a purely local operation. Teams that require a particular dependency-management interface, source layout, or host integration outside the documented GitHub variables should verify compatibility before adopting niv.

## Maintenance, licensing, and operational limits

The repository is not archived, and its last push was on 2026-09-11. The repository metadata does not list any GitHub releases. The README states version `0.3.0` in the command output, but that is not the same as a GitHub release record. The repository includes `CHANGELOG.md`, `HACKING.md`, a test script, a Cabal file, and a Nix development setup, but the README does not describe the contents or guarantees of those files.

The project is licensed under MIT. That identifies the repository’s stated license, but it does not replace checking the license file or dependencies when legal requirements matter. The README also does not document a rollback command. If an update records an unintended revision, the visible project state can be reviewed in `nix/sources.json`, but the README does not promise an automated revert.

Network access is another operational boundary. GitHub API authentication can be supplied through `GITHUB_TOKEN` or `NIV_GITHUB_TOKEN`. The host and path variables indicate that non-default GitHub services may be supported, but the README gives no complete configuration example. Secure API requests default to port `443`, while insecure requests default to port `80`, and `NIV_GITHUB_INSECURE` switches requests to `http` when set to a non-empty value. These are configuration details to verify against the intended environment.

## Conclusion

Adopt niv when a Nix project needs a simple, file-based record of pinned remote sources and does not require the full flakes workflow. Do not choose it when automatic source updating, GitHub metadata resolution, or private GitHub access is essential unless the relevant network and authentication conditions are available. The first checks are whether nix/sources.json can be committed, whether the selected branch and revision match the intended dependency policy, and whether a clean `niv update` produces a reviewable change.

## FAQ

### What is niv used for in a Nix project?

niv tracks and pins external dependencies such as URLs and GitHub repositories in `nix/sources.json`. It can be used in Nix projects with or without flakes.

### How do I install niv and initialize a Nix project?

The README documents installing it with `nix-env -iA nixpkgs.niv`, then running `niv init`. Initialization creates `nix/sources.json` and `nix/sources.nix`, with nixpkgs recorded in the source file.

### How do I add and update a dependency with niv?

Use `niv add stedolan/jq` for a GitHub repository or `niv add` with `-v` and `-t` for a custom URL template. Use `niv update nixpkgs` to update an entry and `niv update nixpkgs -b master` to select another branch.

### Does niv support private or non-default GitHub hosts?

The documented environment variables include `GITHUB_TOKEN`, `NIV_GITHUB_TOKEN`, `GITHUB_HOST`, `GITHUB_API_HOST`, `GITHUB_API_PORT`, `NIV_GITHUB_INSECURE`, and `NIV_GITHUB_PATH`. The README documents these settings but does not provide a complete private-host example.

### Can niv rollback a dependency update?

The README documents `add`, `update`, `drop`, `init`, `show`, and `modify`, but it does not document a rollback command. It also does not explain whether `modify` can reverse a prior revision change.

## Sources

- [Issues](https://github.com/nmattia/niv/issues)
- [License: MIT](https://github.com/nmattia/niv/blob/main/LICENSE)
- [nmattia/niv on GitHub](https://github.com/nmattia/niv)
- [Project website](https://github.com/nmattia/niv)
- [README](https://github.com/nmattia/niv/blob/main/README.md)

---

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