I remember from using Nix long ago that when you “uninstall” a package, you don’t really “uninstall” it – you just remove the symlinks to it in your
~/.nix-profile/bin directory, so it no longer appears on your
Now I know that it doesn’t “remove symlinks” but rather “builds a new user environment and changes the
~/.nix-profile symlink to point to the new generation’s symlink to that user environment.” But you know, effectively the same thing. So there is a separate operation to actually delete those files, and remove the old generations.
Let’s find out more.
Chapter 11. Garbage Collection
In the quick start guide I learned that I could use:
$ nix-collect-garbage --delete-old
And now I know that
--delete-old means “hey but before you collect garbage, also delete old generations of my profile.”
Now I’m learning that I can do the
--delete-old step myself, if I want, by using
nix-env --delete-generations, and I can trigger the garbage collection by using
nix-store --gc. This is my first encounter with
nix-store, but the separation makes some sense to me:
nix-env deals with my environment – stuff in my
~/.nix-profile – but the store is bigger than just that. It will eventually have things from
nix-shell files, other users, or whatever.
So, alright. I suppose that
nix-collect-garbage is its own command because it does both environment things and store things and it would be weird to have a single command that does both. Aside from, you know,
Anyway. This has an example of an interesting command:
$ nix-env --delete-generations 14d
To delete generations older than two weeks.
Apparently generations know how old they are? Which is strange: previously I was able to convince myself that these were just symlinks. I apparently forgot that when I ran
nix-env --list-generations, it showed me a timestamp. Where is that timestamp stored? It’s not in the user-environment: if it were, I wouldn’t have seen the duplicated environments when I looked at my symlinks. This “Nix database” character is starting to look suspicious again.
Oh. Right. Duh.
It’s the creation date of the symlink, isn’t it?
Thanks, filesystems. Still no evidence of any database here.
See? Unedited stream of consciousness. No matter how dumb it makes me look.
Let’s move on from that. Quickly.
The behaviour of the gargage collector [sic] is affected by the
keep-derivations(default: true) and
keep-outputs(default: false) options in the Nix configuration file.
The Nix configuration file?? What’s that?
This is the first I’d heard of this. Where is this file? What else can I configure?
I investigate likely sources – it wouldn’t be in my home directory, since these decisions feel bigger than me. I try to see if it’s in
/nix… which leads me only to
/nix/var/nix. And here I see a folder called
Aha! The Nix database is real! What a rollercoaster this has been.
I go on a tangent. There is a file
/nix/var/nix/db/schema – I open it excitedly. But it just turns out to be a version number. Boo. There is also a file called
big-lock, which earns my wholehearted approval. That’s a good name.
My curiosity gets the better of me and I briefly forget about the Nix configuration file – I open up the Nix database.
And it’s just a bunch of
^@ signs! I can’t make sense of any of this. Yuk yuk yuk.
$ sqlite3 /nix/var/nix/db/db.sqlite '.schema'
CREATE TABLE ValidPaths ( id integer primary key autoincrement not null, path text unique not null, hash text not null, registrationTime integer not null, deriver text, narSize integer, ultimate integer, -- null implies "false" sigs text, -- space-separated ca text -- if not null, an assertion that the path is content-addressed; see ValidPathInfo ); CREATE TABLE sqlite_sequence(name,seq); CREATE TABLE Refs ( referrer integer not null, reference integer not null, primary key (referrer, reference), foreign key (referrer) references ValidPaths(id) on delete cascade, foreign key (reference) references ValidPaths(id) on delete restrict ); CREATE INDEX IndexReferrer on Refs(referrer); CREATE INDEX IndexReference on Refs(reference); CREATE TRIGGER DeleteSelfRefs before delete on ValidPaths begin delete from Refs where referrer = old.id and reference = old.id; end; CREATE TABLE DerivationOutputs ( drv integer not null, id text not null, -- symbolic output id, usually "out" path text not null, primary key (drv, id), foreign key (drv) references ValidPaths(id) on delete cascade ); CREATE INDEX IndexDerivationOutputs on DerivationOutputs(path);
No idea. Truly no idea. Definitely not ready for this. But it’s nice to see how small it is! And that there seems to be nothing user-specific – all store-wide things. So I didn’t learn… nothing, by doing that. But still: let’s abort; let’s get back on course.
I still haven’t found the configuration file. Maybe I have to create one? Maybe there is no configuration file by default.
I grep for likely strings in
man nix-env – wouldn’t it be nice if there were just a
man nix? That would tell me things like this? Anyway. I follow a pointer to
man 5 nix.conf, which tells me it’s
sysconfdir? It offers an example –
/etc/nix/nix.conf – but that’s not there. I google the term
sysconfdir because I’ve never heard it before. That leads me to
/usr/local/etc. But: no joy.
I feel like there should be a command to just print the path of the current configuration file, but no such command is listed in
man 5 nix.conf.
The man page for
nix-env tells me that I can use
NIX_CONF_DIR to change the location, and that that defaults to
prefix/etc/nix, contradicting what
man 5 nix.conf said.
prefix is not defined, but from reading the descriptions of the other environment variables I conclude that this means
And I have no
/nix/etc, so I have now decided that I have no
nix.conf file. I must just be using all defaults.
man 5 nix.conf gives an example of a config file that I could use:
keep-outputs = true # Nice for developers keep-derivations = true # Idem
That comment is intriguing. I allow myself to be briefly amused by the idea of someone who is not a professional software developer using Nix, before returning to the manual:
The defaults will ensure that all derivations that are build-time dependencies of garbage collector roots will be kept and that all output paths that are runtime dependencies will be kept as well. All other derivations or paths will be collected. (This is usually what you want, but while you are developing it may make sense to keep outputs to ensure that rebuild times are quick.)
Okaaaay. I assume this is the “Nice for developers” comment above. But I don’t really understand what that means. Why does… keeping outputs mean that rebuild times will be quick? What are “outputs”?
I am also sort of surprised that it keeps build time dependencies around – I suspect this is useful mostly because so many packages share them? Or so that
--upgrade is faster? If I got a package from a binary cache, do I still get the build-time dependencies?
This seems like a potential waste of space.
$ du -hcd 0 /nix du: /nix/.Spotlight-V100: Operation not permitted du: /nix/.Trashes: Operation not permitted du: /nix/.fseventsd: Permission denied 1.1G /nix
And so far the only package I’ve installed is
I mean, I assume most of that is whatever
nix-shell installs, which I hope to learn more about. I expect if I collected garbage right now, that would go down considerably, but then I would be annoyed the next time I ran
The chapter closes with an example of
nix-collect-garbage -d, which it defines as “a convenient little utility.” And it is!
At the end of this I should make a bestiary of all the
nix-* commands. Clearly
nix-env is the main powerhouse.
nix so far has a search function and nothing else.
nix-store sounds like a low-level plumbing command – but there are a bunch more, and I don’t know which are “little utilities” and which are fundamental commands that the others wrap. But! By the time I finish reading this manual, hopefully I will.
Anyway. Next we learn about garbage collector roots, and I am delighted to learn that the way you register new GC roots is by using
ln -s. Yep! Make a symlink! You’re an adult! What, you thought there would be a
nix add-gc-root command? Please. The manual gives a weird example of how to add a new root:
$ ln -s /nix/store/d718ef...-foo /nix/var/nix/gcroots/bar
(It’s weird to me that the root is called
bar but the store path is
So that’s… fine. That’s pretty much all there is in this section. There’s nothing about how to make the GC include the stuff that
nix-shell needs. Or even… what those things are. Do not know. I still hope to find out, but I’m a little sad that I didn’t find out in this section.
- Where is the Nix configuration file?
- What are “outputs” (as in
- What does
keep-derivationsdo? I’m still not really clear on the term “derivations”.
- When I get a binary cached package, do I still download and keep all the build-time dependencies?