Nix Garbage Collection: Free Up Disk Space

by Admin 43 views
Nix Garbage Collection: Free Up Disk Space

Hey everyone! So, I've been a bit of a slacker lately when it comes to managing my Nix environment, specifically the Nix garbage collection. You know how it is, life gets busy, and sometimes those little maintenance tasks slip through the cracks. But lately, I've been thinking it's probably a really good idea to get a handle on this, even though my SSDs are currently shouting "We have PLENTY of space!". It’s always better to be proactive, right? Plus, this feels like the perfect moment to dive deep into Nix settings and see if there are any other hidden gems that could make our lives easier. So, grab a coffee, settle in, and let's talk about how we can keep our Nix systems lean and mean.

Why Bother With Nix Garbage Collection Anyway?

Alright guys, let's get down to brass tacks. You might be wondering, "Why should I even care about garbage collection in Nix?" Well, think of your Nix store (/nix/store) like a massive, ever-growing library. Every time you install a package, build something, or even update your system, Nix adds new books (or rather, packages and their dependencies) to this library. The problem is, Nix is incredibly smart and keeps track of everything. This means that even if you uninstall a package, its older versions or some of its dependencies might still be hanging around in the store, just in case you need them for a rollback or if another package still relies on them. This is a super powerful feature, allowing for atomic upgrades and easy rollbacks, which is honestly one of the biggest reasons I love Nix. However, over time, this can lead to a significant amount of disk space being consumed by stuff you might not actually need anymore. Nix garbage collection is essentially the process of identifying and removing these unreferenced or old generations of packages from your /nix/store, freeing up valuable disk space. It's like decluttering that massive library – removing books that are no longer borrowed, are outdated, or have been replaced by newer editions. Neglecting this can lead to a bloated store, slower operations, and in extreme cases, running out of disk space, which is never a fun experience. So, optimizing Nix settings for garbage collection isn't just about saving space; it's about maintaining a healthy and efficient Nix system. It’s a crucial part of the Nix lifecycle that ensures you’re only keeping what you actively use or might need for a specific, defined purpose. It’s about striking a balance between Nix’s powerful immutability and the practical reality of finite disk space. Plus, who doesn't love having more space for cool new projects or just a faster system overall? It’s a win-win, really.

Getting Your Hands Dirty: Manual Garbage Collection

So, you've decided to take the plunge and manually initiate garbage collection. Awesome! It's actually pretty straightforward, and doing it yourself gives you a direct understanding of what's happening. The primary command you'll be using is nix-collect-garbage. Now, this command is pretty smart on its own, but you can give it some instructions. By default, nix-collect-garbage will remove all unreferenced store paths that are not currently kept by any garbage collection roots. What are these roots, you ask? Think of them as the things Nix definitely doesn't want to delete. This includes things like your currently active system generations, profiles you've explicitly kept, and any other paths explicitly registered as roots. To run a basic garbage collection, you just type:

nix-collect-garbage

This will scan your Nix store, figure out what's unreferenced, and then ask for your confirmation before deleting anything. It’s a good idea to run this periodically, maybe once a month, or whenever you feel like your disk space is starting to dwindle. Now, sometimes you might want to be a bit more aggressive. For instance, you might want to get rid of old generations of your system or profiles. Nix keeps track of different versions of your system configurations, and these can take up a surprising amount of space. You can tell nix-collect-garbage to also collect old generations using the -d or --delete-older flag. This command will remove all store paths that are not referenced by any other store path that is newer than the specified date. If you don't specify a date, it defaults to deleting all generations older than the current one. This can be a bit drastic if you're not careful, so make sure you know what you're doing! A common and safer approach is to clean up old system generations specifically. You can do this using nix-env --delete-generations old for user environments or by managing system generations via your NixOS configuration if you're on NixOS. For NixOS, you can specify a maximum number of generations to keep. For example, in your configuration.nix, you might add:

boot.loader.grub.configurationLimit = 5; # Keep only the latest 5 generations

This is a fantastic way to automate the cleanup of old system boots. Remember, Nix garbage collection is a powerful tool, and using flags like -d requires a bit more understanding of what you're deleting. Always make sure you have backups or are confident in your current system state before running more aggressive garbage collection commands. It's also a good practice to run nix-store --optimise after garbage collection. This command optimizes the Nix store by hard-linking identical files, which can save a bit more space and potentially speed up access to your packages.

Automating the Cleanup: Scheduled Garbage Collection

Manually running nix-collect-garbage every now and then is great, but let's be honest, we're all a bit lazy sometimes. We forget, or we just don't feel like typing commands. The good news is, you can automate this whole process! This is where Nix settings come into play to make your life so much easier. NixOS, being the wonderfully configurable system it is, provides a straightforward way to schedule garbage collection. You just need to add a few lines to your configuration.nix file. The key settings here are nix.gc.automatic and nix.gc.dates. By setting nix.gc.automatic to true, you're telling NixOS to enable automatic garbage collection. This is the magic switch that turns on the scheduled cleanups.

Next, you can control when this automatic garbage collection happens. The nix.gc.dates setting allows you to specify a cron-like schedule. You can set it to run daily, weekly, or on specific days and times. For instance, if you want garbage collection to run every Sunday at 3 AM, you could set it like this:

nix.gc.automatic = true;
nix.gc.dates = "Sun *-*-* 03:00:00";

This configuration will ensure that your Nix store is regularly cleaned up without you having to lift a finger. It's a set-and-forget kind of deal! If you want it to run daily, you could use something like "*-*-* 04:00:00" to run it every day at 4 AM. You can also specify multiple dates if you want it to run more frequently. For example, to run it every Sunday and Wednesday at 3 AM:

nix.gc.dates = "Sun *-*-* 03:00:00, Wed *-*-* 03:00:00";

There's also a setting called nix.gc.options where you can pass additional arguments to nix-collect-garbage. For example, if you want to automatically delete old generations along with unreferenced paths, you could add "--delete-older-than 30d" to delete anything older than 30 days. Be careful with this one, as it can remove quite a bit! A more common option is to just let it run without aggressive deletion flags unless you specifically need it.

nix.gc.options = "--delete-older-than 7d"; # Example: delete unreferenced paths older than 7 days

Remember to rebuild your NixOS system after making these changes using sudo nixos-rebuild switch. If you're not on NixOS but still want to automate, you can set up your own cron jobs or systemd timers that execute nix-collect-garbage with your desired flags. This gives you the same benefits of automated cleanup, ensuring your disk space stays healthy without manual intervention. It’s all about making Nix settings work for you, not the other way around!

Fine-Tuning: Advanced Nix Garbage Collection Settings

Beyond the basic automatic scheduling, there are more advanced Nix settings you can tweak to really dial in your garbage collection process. These options offer finer control and can be particularly useful for users with specific needs or large, complex Nix environments. One of the most impactful settings relates to how long Nix keeps old generations. As we touched upon earlier, Nix keeps multiple generations of your system and user profiles. While this is fantastic for rollbacks, it can be a significant source of disk space usage. NixOS provides options to manage this directly. For instance, you can limit the number of boot entries in the GRUB menu, which indirectly influences how many system generations are kept readily accessible. The boot.loader.grub.configurationLimit option, as mentioned, is one way to do this. However, you can also configure Nix itself to manage how many user package generations are kept. The nix.env.max-jobs and nix.env.keep-derivations settings, while not directly garbage collection, influence the build process and can indirectly affect the number of intermediate build products. A more direct approach for managing old generations is often done at the Nix channel or profile level. For instance, you can use nix-env --profile /nix/var/nix/profiles/default --delete-generations 3 to keep only the three most recent generations for your default user profile. For NixOS systems, the nix.gc.automatic setting implies that nix-collect-garbage is run, and you can pass specific options to it via nix.gc.options. A very useful option here is --delete-older-than. This flag tells nix-collect-garbage to remove any unreferenced store paths that haven't been accessed or modified in a certain period. Setting this to something like --delete-older-than 30d (30 days) can be a good balance between keeping recent history and freeing up space.

nix.gc.automatic = true;
nix.gc.dates = "*-*-* 04:00:00"; # Daily at 4 AM
nix.gc.options = "--delete-older-than 30d"; # Delete unreferenced paths older than 30 days

Another setting to be aware of is nix.binary-caches. While not directly for garbage collection, ensuring your binary caches are configured correctly can reduce the number of packages you need to build locally, thus reducing the number of intermediate build products that might otherwise become garbage. For users managing large projects or multiple development environments, you might also encounter the concept of keep-derivers. This option, often set via NIX_KEEP_DERIVERS=1 environment variable or within Nix configuration, tells Nix to keep the build products (derivers) of derivations even if they are not directly referenced by a profile or system generation. This can be useful if you have specific build artifacts you want to preserve but aren't actively using in a profile. Configuring Nix garbage collection effectively often involves understanding these nuances. It's about finding the right balance for your workflow. For example, if you frequently experiment with different package versions, you might want to set a generous --delete-older-than value or rely on manual collection for older generations. If you're on a system with limited storage, you'll want to be more aggressive. The key is to monitor your disk usage and adjust these Nix settings accordingly. Don't be afraid to experiment, but always understand the implications of each setting before applying it. Remember to run sudo nixos-rebuild switch after modifying NixOS configurations.

Beyond Garbage Collection: Other Disk Space Savers

While Nix garbage collection is a superhero when it comes to reclaiming space in your /nix/store, it's not the only tool in your arsenal for managing disk space. Sometimes, the culprits aren't just old package versions; they can be large build caches, temporary files, or even large Nix derivations that are still technically referenced but unnecessarily consume space. Let's chat about a few other handy tricks, guys.

One of the first things to consider is the Nix build cache. Nix can cache the results of your builds. While this is incredibly fast for subsequent builds, these caches can grow quite large over time, especially if you build many different packages or configurations. You can clean up the Nix build cache using nix-collect-garbage -d which also removes old generations, or more specifically, you can use nix-store --gc for a more targeted garbage collection of the Nix store itself. However, for build caches, you might look into tools or configurations that manage the build directory (/nix/var/nix/profiles/per-user/<user>/build-cache or similar). While nix-collect-garbage primarily targets the /nix/store, and its automatic version often cleans up profiles, it's worth noting that build artifacts that are temporarily needed during a build but not kept by any final derivation should be garbage collected. If you suspect build caches are an issue, manually inspecting /nix/var/nix/ for large subdirectories related to builds might be informative. Another area is Nix Flakes. If you're using Nix Flakes, the flake.lock file pins specific versions of inputs. Over time, as you update flakes, old input versions might remain in the Nix store if not properly garbage collected. Regularly running nix-collect-garbage is essential for keeping these tidy. Furthermore, consider the size of your Nix profiles. A profile is a collection of packages or system generations. If you have many user profiles or system generations, they can add up. Regularly cleaning up old user profile generations using nix-env --delete-generations <generations> or by managing NixOS system generations (as discussed) is vital. For NixOS, remember that nix.gc.automatic = true; typically handles the cleanup of system generations and unreferenced store paths. However, nix-env --profile /nix/var/nix/profiles/default --delete-generations old is useful for cleaning up your user environment generations.

Another handy command, although not directly garbage collection, is nix-store --optimise. This command goes through your Nix store and replaces duplicate files with hard links. This is super effective for saving space if you have multiple packages that share identical libraries or files. It doesn't remove anything, but it consolidates duplicates. You can run this after nix-collect-garbage for an extra bit of space-saving magic. Lastly, let's not forget about large Nix derivations themselves. Sometimes, a package might be large, or a build process might generate very large intermediate files that don't get cleaned up. If you're building custom packages, review their build steps to ensure they're not unnecessarily bloating the store. For instance, ensure that build environments are clean and only necessary outputs are kept. Optimizing Nix settings for disk space goes beyond just running nix-collect-garbage; it's a holistic approach to managing your Nix environment, from automated cleanups to optimizing individual derivations and profiles. Keep an eye on your disk usage, and don't hesitate to explore these other avenues when space starts to feel tight!

So there you have it, guys! A comprehensive rundown on Nix garbage collection and related Nix settings. By understanding why it's important, how to do it manually, and how to automate it, you can keep your Nix system running smoothly and your disk space happy. Happy Nixing!