← Back

Daily driving NixOS

10/11/25

9 min read

I recently decided to install NixOS on my laptop.

Why

I’ve been running Debian for a while, mainly for the stability. I am a college student and cannot afford to break my install after messing up a configuration.

The primary reason for the switch is because I was interested in making my whole setup declaritive. More recent packages were a nice bonus.

Configuration

NixOS is configured by two files: configuration.nix and hardware-configuration.nix.

configuration.nix is filled with all options that makes your install, hardware-configuration.nix should not be changed as it was automatically generated by the NixOS installer.

I split up my configuration into multiple files and directories.

nixos (main) -> tree
.
├── configuration.nix
├── desktop.nix
├── hardware-configuration.nix
├── packages
   ├── core.nix
   ├── desktop.nix
   └── school.nix
├── system
   ├── audio.nix
   ├── boot.nix
   ├── locale.nix
   └── networking.nix
└── users.nix

Now my configuration (and packages) are organised based on how I use them.

Flakes

If you read one of my previous posts My custom tool that makes college easier you know that I made a productivity script for my college workflow.

This script worked just fine after switching to NixOS, just like the scripts I made for my Eww bar.

After learning about flakes I couldn’t wait to make all of these scripts declaritive.

setup-for-college (main) -> tree
.
├── flake.lock
├── flake.nix
├── readme.md
└── setup-for-college.sh

Check out the source code on Github.

{
	description = "tool that makes it easier to manage semesters and courses";
	inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05";

	outputs = { self, nixpkgs }: {
		defaultPackage.x86_64-linux = self.packages.x86_64-linux.setup-for-college;

    	packages.x86_64-linux.setup-for-college =
			let
        		pkgs = nixpkgs.legacyPackages.x86_64-linux;
        		name = "setup-for-college";

        		scriptContent = builtins.readFile (self + "/setup-for-college.sh");
        		script = pkgs.writeShellScriptBin name scriptContent;
        		buildInputs = with pkgs; [ ];
			in pkgs.symlinkJoin {
        		name = name;
        		paths = [ script ] ++ buildInputs;
        		buildInputs = [ pkgs.makeWrapper ];
        		postBuild = "wrapProgram $out/bin/${name} --prefix PATH : $out/bin";
      		};
	};
}

You can specify dependencies via the buildInputs list. This makes sure that the required packages are installed before running the script.

This snippet shows you the buildInputs for my bar-modules script. It requires networkmanager (to use nmcli), alsa-utils (to use amixer) and bspwm (to use bspc).

buildInputs = with pkgs; [ networkmanager alsa-utils bspwm ];

Check out the source code on Github.

I completely rewrote my logic for the modules on my bar. Before the refactor it consisted of completely seperate scripts. I made functions for each module and merged them via one logic.sh script.

Conclusion

Overall I am enjoying the change of mindset (imperative to declaritive), thanks for reading this post!