Why I Use NixOS: A Practical Guide to Configuration, Security, and Reliability

Over the years, I’ve explored various Linux distributions—from Ubuntu and Arch to Gentoo—each with its own strengths and quirks. Along the way, I encountered familiar challenges: configuration drift, unpredictable updates, and the need to rebuild environments from scratch. That search for stability and repeatability led me to NixOS.
This article is intended as a practical overview of:
What NixOS offers and how it differs from traditional distributions.
Configuration management with declarative settings and flakes.
Security benefits through reproducible builds and transactional upgrades.
Reliability features, including rollbacks and garbage collection.
Performance considerations with caching and distributed builds.
Advanced scenarios, such as per-user environments and cross-platform builds.
Tips for migration and common pitfalls to avoid.
Guidance on whether NixOS might suit your needs.
I’ve aimed to keep this guide grounded, focusing on real-world use cases and examples.
1. Understanding NixOS
NixOS is a Linux distribution built on the Nix package manager, which treats packages and configurations as functions. Instead of installing software into mutable directories, NixOS stores each package in an immutable, content-addressed store (/nix/store
).
Functional model: Packages depend only on their explicitly declared inputs.
Immutable outputs: Upgrades create new store entries, leaving previous versions intact.
Garbage collection: Unused package versions can be removed safely.
This design can simplify maintaining consistency across multiple machines.
2. Declarative Configuration
Rather than issuing commands one by one, NixOS uses configuration files to define system state. A typical configuration.nix
might include:
{ config, pkgs, ... }:
{
imports = [ ./hardware-configuration.nix ];
networking.hostName = "workstation";
time.timeZone = "America/New_York";
users.users.maxwell = {
isNormalUser = true;
extraGroups = [ "wheel" "networkmanager" ];
hashedPassword = "<your-hash>";
};
services.openssh.enable = true;
services.openssh.passwordAuthentication = false;
environment.systemPackages = with pkgs; [ vim git curl ];
services.firewall.enable = true;
security.sudo.wheelNeedsPassword = false;
system.stateVersion = "23.11";
}
Running:
sudo nixos-rebuild switch --flake .#workstation
applies all changes atomically. There’s less risk of manual errors, and it’s easy to reproduce the same setup on another machine.
Flakes for Reproducibility
Flakes provide a standard structure for Nix projects. An example flake.nix
:
{
description = "My NixOS configuration";
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11";
outputs = { self, nixpkgs, ... }:
let pkgs = import nixpkgs { system = "x86_64-linux"; };
in {
nixosConfigurations.workstation = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [ ./configuration.nix ];
};
};
}
This makes the configuration portable and version-controlled in one repository.
3. Security Advantages
NixOS can improve security through:
Reproducible builds: You can verify package hashes and audit dependencies.
Transactional upgrades: If an update causes issues, rolling back is straightforward.
Immutable system state: Manual changes are discouraged; the configuration file is the source of truth.
Auditability: All changes are tracked in version control.
For environments that require strict change control, these features can reduce unexpected behavior.
4. Reliability and Rollbacks
NixOS tracks each set of configuration changes as a generation. You can list and switch between generations:
sudo nix-env --list-generations
sudo nix-env --switch-generation <number>
Older generations remain available until you collect garbage:
sudo nix-collect-garbage --delete-older-than 30d
This makes it safer to experiment with updates.
5. Performance and Scalability
Binary caches: Use public caches or host a private cache to avoid rebuilding large packages locally.
Distributed builds: Set up build machines to share workloads via remote builders.
Incremental rebuilds: Only modified packages and dependencies rebuild, saving time.
These capabilities help when managing multiple systems or running continuous integration.
6. Advanced Use Cases
Home Manager: Manage user dotfiles and applications declaratively, alongside system configuration.
Nix User Repository (NUR): Tap community-maintained overlays for specialized packages.
Cross-compilation: Build ARM or other architecture binaries from a single host.
Lightweight deployments: Create minimal container or firmware images with reproducible builds.
Each feature can be adopted incrementally to suit your workflow.
7. Migration and Troubleshooting
Migrating from another distro:
Identify core services and packages you use.
Start with a minimal NixOS VM and replicate key services.
Test each service’s configuration before fully switching.
Keep changes in version control for easy rollback.
Common pitfalls:
Pinning the correct Nixpkgs version is important to avoid unexpected updates.
Hardware configuration files may need updating when hardware changes.
Expect a learning curve; start small and build confidence.
8. Is NixOS Right for You?
Consider NixOS if:
You manage multiple or critical systems that need consistency.
You value reproducibility and clear version control of your infrastructure.
You are willing to invest time learning a declarative paradigm.
You might opt for a different distro if:
You need a quick setup for casual desktop use.
You prefer imperative package management with GUIs.
You have limited time to learn new tools.
9. Getting Started
Official Manual: https://nixos.org/manual/nixos/stable/
Zero to Nix: https://zero-to-nix.com/
NixOS Wiki: https://nixos.wiki/
Community Forums: https://discourse.nixos.org/
Thank you for reading. I hope this guide helps you decide whether NixOS can bring more predictability and control to your projects.