Switching from Ubuntu to NixOs

New Distro

I ditched Ubuntu after five trouble-free years to try something new. I didn’t want another Debian-based distro like Pop!_OS, Mint, or Debian itself. I heard about NixOS, a distro that lets you declare your system configuration and roll back changes if things go south. It sounded too good to be true, but it’s real! Sure, it has rough edges, but for development tasks, it’s a game-changer. I’ll use “NixOS” and “Nix” interchangeably here, as some features come from the Nix package manager, rather than the distro itself. If you like what you hear, you can install Nix on any system to test it out, it’s super easy. Overall, my experience with NixOS has been a delight, quirks and all.

The good

Declaration

The killer feature of NixOS is its declarative approach. Instead of cobbling together bash scripts or Ansible playbooks and praying your setup works, you define your system in a single configuration file. Want a package? Declare it, and NixOS makes it happen. No more sudo apt update && sudo apt install some-package, only to find it’s missing, so you try sudo snap install some-package, get a two-year-old version, and end up running a shady curl -fsSL http://sketchy-site.trustmebro/root-script | sudo sh to get the latest release. NixOS eliminates that chaos. I was sold the moment I saw my system spin up exactly as I described it.

Isolation

Nix’s isolation is mind-blowing. You can install multiple versions of the same app on one machine without conflicts. Coming from the Python world, this is a dream, no more forgetting to activate a virtual environment and accidentally running pip install system-wide. Say goodbye to juggling Conda or Pyenv to manage Python versions. While this is more a Nix feature than NixOS-specific, it’s a huge win for developers.

Ephemerals venvs

Nix lets you spin up temporary virtual environments with a single command. Want to test a hot new tool without committing? Run nix-shell -p newShinyThing, and you’re in a sandbox with that tool ready to go. Too lazy to type that every time? Nix has you covered:

  1. Create a flake.nix to define your environment
  2. Add a .envrc file with:
use flake
  1. Run
direnv allow

Boom! You’ve got a virtual environment that auto-activates whenever you enter the directory. It’s like magic.

Rollbacks

NixOS’s rollback feature is a safety net for the ages. Mess up an update? No sweat, just revert to a previous working version. It gives you the freedom to experiment without fear of breaking your system. Pro tip: track your configuration files with Git otherwise you’ll suffer.

The bad

Awfull docs

NixOS’s documentation is a hot mess, incomplete, confusing, and scattered. You think you’ve found a reliable source on nixos.wiki? Gotcha! That’s not the official wiki (go to wiki.nixos.org instead). Many comments on forums boil down to “here’s my config, copy it, and good luck.” It’s frustrating, especially for newcomers trying to understand the system.

The ugly

Too many abstractions layers

Nix’s promise of reproducible builds is fantastic when you just want to install something and move on. For simple apps with basic customization (like Waybar or Hyprland), declaring colors and sizes in a config file works great. But for complex tools like Neovim, where I want to add custom Lua scripts and functionality, Nix becomes a headache. You’re either concatenating strings to generate Lua code (losing LSP features like autocompletion) or diving deep into Nix’s internals to do it “the Nix way.”

Updates

NixOS’s update system is all-or-nothing. You can’t update a single app or package; it’s the entire system or bust. Want to grab the latest version of one tool? Tough luck, you’re updating everything or sticking with what you’ve got. It’s a bummer when you just need a quick fix.

Home-manager

I have mixed feelings about Home Manager, a tool for managing user configurations declaratively. The idea is awesome, but the execution? Not so much. My gripes:

  • It’s yet another abstraction layer that’s similar to NixOS’s system config but just different enough to be annoying.
  • Every time I tweak a config file to test a new setting, I have to rebuild the entire Home Manager setup.

It’s tedious, especially for frequent changes. I’m starting to question if I need this extra layer. I like the concept, but when I’m tweaking configs, it feels more like a chore than a convenience.

Flakes

Flakes are a powerful but experimental feature in Nix. They let you define reproducible, versioned environments for projects, like a supercharged package.json or requirements.txt. Combined with direnv, you can have a programming language environment (e.g., Python, Rust, Node.js) ready to go with a single command, all tracked in a flake.nix file. It’s a dream for keeping project dependencies consistent. However, Flakes are still rough around the edges, with quirks in tooling and documentation. I’ve heard great things about Determinate Systems for improving the Flake experience and Nix CLI, but I haven’t tried their tools yet.

Next steps

I’ve only scratched the surface of Nix and NixOS. There’s so much more to explore, like better project packaging so I can ditch tools like Nvf for managing Neovim (it’s a great package, don’t get me wrong, but I want more control over my Neovim). I love Neovim (I use Neovim btw), but Nvf adds too much abstraction. String concatenation for Lua scripts is clunky when I could just write Lua directly.

I’m also eyeing infrastructure projects, like managing remote machines or setting up a Kubernetes/Docker Swarm-like homelab with Nix. The idea of a fully declarative homelab sounds insanely cool, and I’m eager to see if there’s an existing solution or if I’ll need to roll my own. Thanks for reading about my NixOS journey! It’s been a wild ride, and I’m hooked despite the bumps. Stay tuned for more adventures in declarative bliss (and occasional frustration).