Add a file to the nix store (permanently)
How to add a file to the nix store and have it survive garbage collection.
If you have proprietary software which you would like to install on your nixos you are going to run into an issue: there is likely no public url for you to download the files from. Given this you are probably going to want to download the file and put it in the nix store manually so your derivations can reference it. For some reason I found this to be rather difficult to figure out how to do. I also did it wrong and garbage collection just blew away my custom fonts. This article is written so I never have to remember how to do this again. If you want to skip the reading, here’s a worked example.
Add a file to the store
The fancy new nix 3 command line has the store
subcommand which lets you
manipulate the store. nix store --help
reveals that there are the following
subcommands:
· nix store add-file - add a regular file to the Nix store
· nix store add-path - add a path to the Nix store
Surely one of these is what we want, right? Maybe! For reasons I don’t really
understand these two commands are missing some of the features the older
command had… For that reason the best tool to use (in my experience) is
nix-prefetch-url
. The man pages say about everything you want, here’s what I
find useful.
-
It is meant to be run with urls, local files will have a url structure like
file:/absolute/path/to/file.zip
-
The name of the prefetched file has to match the name of the file in your
derivation, not just the hash. This took me a hot minute to figure out. You
can force the name of the imported file to be different than the name of the
original file with the
--name
option. -
If the file is an archive you probably want the
--unpack
flag, this will make it compatible withfetchzip
and the like. -
To get the path of the file in the store (which you will need to register a
GC root) you need the
--print-path
flag.
Keep that file safe
Great! We got a file into the store, problem: this file has nothing pointing to
it, the nix garbage collector is liable to delete it at a moments notice. To
stop this we need to register a GC root. As far as I can tell there are no
commands in place to do this for you. Let alone do it atomically1.
Turns out a gc root is just a symlink in /nix/var/nix/gcroots
pointing into
the nix store. So this is as easy as:
ln -st /nix/var/nix/gcroots /nix/store/<path>
A worked example
In this example I am pushing a zip file of the lovely butterick fonts into the nix store so I can reference that zip file to install the fonts. First we push the file into the nix store.
$ nix-prefetch-url \
--unpack \
--print-path \
file:/home/ethan/downloads/butterick
1j62qgsvyyza2yzam5rzalky7lgdyxj9gngrzyz0zpqkrnwpz5cx
/nix/store/sb9856q6l3yhzykh83m39rrlsmrhxklz-butterick.zip
Then we register the GC root
$ sudo ln -st \
/nix/var/nix/gcroots \
/nix/store/sb9856q6l3yhzykh83m39rrlsmrhxklz-butterick.zip
I like the SRI hash format used with most nix derivations for some reason… so
we convert the hash from the prefetch step to SRI using nix-hash
.
$ nix-hash \
--to-sri \
--type sha256 \
1j62qgsvyyza2yzam5rzalky7lgdyxj9gngrzyz0zpqkrnwpz5cx
sha256-nZV/uc0T3w++//nZl2T37dHjJ1U/l6q+F+p7v/XDwsg=
Finally we can write a nix expression to reference this file.
fetchzip {
url = " ";
# name has to match the file name...
name = "butterick.zip";
hash = "sha256-nZV/uc0T3w++//nZl2T37dHjJ1U/l6q+F+p7v/XDwsg=";
}
-
Unfortunately the garbage collector could, in theory, run after you add the file but before you register the GC root. This seems unlikely, if it happens you can re-run
nix-prefetch-url
with the broken GC root in place and everything should just work™.↩︎