The Nix Database (db.sqlite)

Updated

September 12, 2026

The Nix Database (db.sqlite)

/nix/store is a directory tree. Nix does not discover it by walking the tree on every command. The boring default is: the daemon owns /nix/var/nix/db/db.sqlite, and you query it with nix-store / nix path-info, never with sqlite3.

Mental model

The database answers three questions:

  1. Is this path valid (registered, complete, not half-copied)?
  2. What does it reference, and what refers to it?
  3. Which .drv derived it?
/nix/store/          bytes
/nix/var/nix/db/     index of those bytes
     db.sqlite
     schema

If you copy files into /nix/store with cp, the database does not know them. nix-store --query will not list them. GC will not preserve them. The next --verify may delete them as garbage.

The daemon holds a lock on the database. That is why two nix-build processes can run at once without corrupting registration. On a multi-user 2.35 install your account talks to the daemon; the daemon talks to SQLite.

Worked examples

Case 1: Referrers — who keeps this path alive?

nix-store -q --referrers $(nix path-info nixpkgs#ripgrep)

Output (shape):

/nix/store/z1k947f6y788sfaivs931h26hsvb3506-ripgrep-14.1.1
/nix/store/…-system-path

A path with no referrers and no GC root is collectable. Profiles and result symlinks show up as referrers once they point here.

nix-store -q --referrers-closure $(nix path-info nixpkgs#hello) | wc -l

That number is “how much of the graph would notice if hello vanished,” not disk size.

Case 2: Valid path check

nix-store --query --hash $(nix path-info nixpkgs#hello)
nix-store --verify --check-contents 2>&1 | tail

--verify --check-contents rehashes every registered path. It is slow; it is the tool you run after a disk scare, not every morning. Without --check-contents it only checks that the directory exists.

Output on a healthy store:

reading the Nix database...
checking path existence...
checking hashes...

No “path is corrupted” lines.

Case 4: Registration is why nix copy exists

mkdir -p /tmp/not-a-store
cp -a $(nix path-info nixpkgs#hello) /tmp/not-a-store/
nix-store -q --requisites /tmp/not-a-store/hello-* 2>&1 || true

Output:

error: path '/tmp/not-a-store/…' is not valid

The bytes exist. Nix does not care. Register them:

nix copy --to file:///tmp/desk-cache nixpkgs#hello
nix path-info --store file:///tmp/desk-cache nixpkgs#hello

That cache has its own database. USB cp of a store directory does not.

Case 5: Where the file lives (look, don’t poke)

sudo ls -l /nix/var/nix/db/

Output:

-rw-r--r-- 1 root root … db.sqlite
-rw-r--r-- 1 root root … schema

Owned by root. You do not sqlite3 this file. After filesystem damage:

sudo nix-store --verify --check-contents

Then restore missing paths from the team cache (nix copy --from …). Do not INSERT rows by hand.

The trap

The trap is opening db.sqlite in a GUI and deleting a row to “free space.” The store directory and the database then disagree. --verify will complain; GC may delete the wrong thing; the daemon may refuse to start.

The other trap is sudo rm -rf /nix/store/some-hash-… because du scared you. The database still lists the path as valid. The next build that expected those bytes fails in a way that looks like a nixpkgs bug.

Use nix-collect-garbage. Use nix-store --delete only on a path with zero referrers, and only when you mean it.

The boring rule

  • Query with nix-store -q and nix path-info. Never write SQL against db.sqlite.
  • Paths that are not registered are not Nix paths, even if they sit under /nix/store.
  • After filesystem damage, nix-store --verify --check-contents. Then restore from a cache, do not patch the DB.
  • Substituted artifacts may lack a deriver. That is normal.
  • Delete via GC, not rm.

Try this

  1. nix-store -q --referrers-closure $(nix path-info nixpkgs#hello) and estimate how much of your profile depends on hello.
  2. Run nix-store --verify without --check-contents (fast existence check). Then decide whether you need the slow rehash.
  3. nix path-info --json nixpkgs#hello and identify narHash, references, and deriver in the JSON.
  4. Attempt nix-store --delete $(nix path-info nixpkgs#glibc) and read the “cannot delete path because it is still alive” error. That error is the database doing its job.