1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
|
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Suckless Nix | Skullheadx</title>
<meta name="description" content="Explaining how I use NixOS in a suckless way.">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="../style.css">
<link rel="icon" href="../favicon.ico">
</head>
<body class="blog">
<div class="blog-wrapper">
<header class="main-head" id="top">
<h1><a href="../index.html">Skullheadx's Blog</a></h1>
</header>
<nav class="main-nav">
<section>
<ul>
<li><a href="../index.html">Main Page</a></li>
<li><a href="./index.html">All Posts</a></li>
<li><a href="../tech/index.html">Technology Posts</a></li>
</ul>
</section>
</nav>
<main class="content">
<article class="blog-post">
<hgroup id="suckless-nix">
<h3>Suckless Nix</h3>
<p>Published: <time datetime="2026-07-04">July 4, 2026</time></p>
</hgroup>
<p>Many people criticize <a href="https://nixos.org">Nix</a>
for being an overcomplicated abstraction and that's absolutely true if you're using Nix the way most people do. This blog post will explore my experience learning to use Nix over 12 months and the 'suckless' configuration I've settled on.</p>
<h4 id="dont-use-home-manager">Don't Use Home Manager</h4>
<p>In my experience, using <a href="https://nix-community.github.io/home-manager/introduction.html">Home Manager</a>
has more negatives than benefits. For example, trying to configure the settings for any program involves this guessing game of what options are supported and how to configure them. Take this snippet from my old home manager configuration:</p>
<div class="code-block">
<pre><code>programs.ghostty = {
enable = true;
settings = {
shell-integration = "fish";
shell-integration-features = true;
mouse-hide-while-typing = true;
cursor-click-to-move = true;
mouse-shift-capture = true;
scrollback-limit = 10000;
link-url = true;
link-previews = true;
background-opacity = 0.8;
background-blur = true;
window-inherit-working-directory = true;
window-save-state = "always";
copy-on-select = "clipboard";
clipboard-read = "allow";
clipboard-write = "allow";
confirm-close-surface = false;
auto-update = "off";
};
};</code></pre>
</div>
<p>The entire <code>settings</code>
block is undocumented and you have to go into the <a href="https://ghostty.org/docs/config/reference">Ghostty Option Reference</a>
and guess how to set it up in the Nix langauge. It was precisely this kind of frustrating experience which really made me consider switching away from NixOS.</p>
<!--There really is no point in using the Nix language here. You are not benefiting from the type system or high level abstraction-->
<h4 id="suckless-software">Suckless Software</h4>
<p>Fortunately, I found out about <a href="https://suckless.org">Suckless Software</a>
and I basically deleted my whole configuration and started over on X11 with a renewed energy to write a minimal, yet powerful Nix configuration.</p>
<p>The <a href=https://suckless.org/philosophy>Suckless philosophy</a>
has a focus on simplicity, clarity, and frugality which helps keep their software easy to maintain, extend, and modify. I believe applying these principles has helped me create a reliable configuration that I can depend on for work, school, personal use, and running a business.</p>
<h5 id="simplicity">Simplicity</h5>
<p>It took me approximately 10 months of daily use to really understand what Nix is and how it works. Nix was my first functional programming language, so I was unfortunate enough to have to struggle to get to where I am today. The trick to grasping Nix is to avoid using fancy features and just stick to basic features as you are getting started; I like to tell people that the best way to use Nix is to use as little of it as possible.</p>
<p>Flakes are one advanced feature that is an exception from this rule because they give you the ability to pin down the exact version of the inputs used, and they let you easily wire up your configuration for different hosts. A Nix flake is literally just an input and output. Inputs are just some urls to some packages like <a href=https://github.com/NixOS/nixpkgs/tree/nixos-unstable>nixpkgs</a>
or my <a href=https://git.skullheadx.com/dwm>dwm</a>
package. The outputs are just a fully configured, installed and setup system like a <code>nixosConfiguration</code>
or a <code>darwinConfiguration</code>.</p>
<p>The way that I solved the problem with Home Manager, and configuring the system in general is to use Nix to do the following:</p>
<ul class="list-disc">
<li>Manage dotfiles, and put them in the right place</li>
<li>Download and install packages, keeping them locked at the right version and isolating their dependencies.</li>
<li>Start services</li>
</ul>
<p>Don't try to write your whole system config in Nix. It's a fool's errand, and gives you almost no benefit since you can't really take advantage of the languages features, besides first class file paths. My first choice is to just use Nix to enable and set just a few settings, but if it starts getting too complicated, I usually use a mix of the documented options like <code>enable</code>
and <code>extraConfig</code>
to use the program's configuration syntax
when I need to merge the two, which Nix can handle beautifully.</p>
<p>For dotfile configuration, I just write them into the <a href=https://git.skullheadx.com/nixos/tree/dotfiles>dotfiles directory</a>
in my git repo, which <a href=https://hjem.feel-co.org>Hjem</a>
copies into the Nix Store and symlinks to the config location that the program looks for. This method allows me to take full advantage of existing documentation for the tools, but also use Nix for the reproducibility and management of dotfiles.</p>
<h5 id="clarity">Clarity</h5>
<p>I was inspired by <a href=https://andrewkelley.me>Andrew Kelley</a>, the creator of <a href=https://ziglang.org>Zig programming language</a>, and his philosophy of not letting the compiler do stuff behind your back. To translate this to a NixOS configuration, I opted to make minimal use of overlays, modules, and functions. As a programmer it's very difficult to resist the urge to not repeat yourself but I've found through experience, that I'd rather just repeat myself once or twice or even three times because it's much easier to maintain. Whenever you add these abstractions, the code doing real work get shoved somewhere else and it becomes confusing with regards to what the code is actually doing because you need to jump somewhere else to understand it. Take my <a href=https://github.com/nix-darwin/nix-darwin>Nix Darwin (MacOS)</a>
configuration where different configurations need different hostnames and usernames:</p>
<div class="code-block">
<pre><code>darwinConfigurations = {
kenosis = nix-darwin.lib.darwinSystem {
specialArgs = {
inherit inputs;
nvim = nvim-darwin;
username = "andrew";
};
modules = [
./common-darwin.nix
./hosts/kenosis/configuration.nix
./overlays.nix
hjem.darwinModules.default
];
};
bear = nix-darwin.lib.darwinSystem {
specialArgs = {
inherit inputs;
nvim = nvim-darwin;
username = "andrewmontgomery";
};
modules = [
./common-darwin.nix
./hosts/bear/configuration.nix
./overlays.nix
hjem.darwinModules.default
];
};
};</code></pre>
</div>
<p>While it is very simple to refactor this into a function, it hides the code away from where I want to see it and be defining the actual configuration, if I need to do a quick fix to add a module.</p>
<p>Also, the code duplication should not really be a problem for personal computing. My flake has 4 configurations for my desktop, homelab, and two laptops, and there are only ~3k LoC. Very manageable.</p>
<p>Something that I really appreciate about Nix, and NixOs is that it lets you say <code>services.program-here.enable = true;</code>, and it will make the systemd timers and services for you, but it also lets you have full control to write them yourself. This simplicity of turning on a service with one line, but also the ability to have deep level of control, lets me feel safe, knowing that I can tweak it if I need to. While this point seems a bit contradictory to the goal of absolute clarity, I think that the level of abstraction is tasteful enough that I don't mind Nix doing a little bit of stuff behind my back, since I can rip it out and replace it with my own whenever I like.</p>
<h5 id="frugality">Frugality</h5>
<p>Something I've noticed when using X11 is that the extremely mature ecosystem has plenty of great tools that just do exactly what you need them to do. For example <a href=https://github.com/baskerville/sxhkd>Simple X Hot Key Daemon (sxhkd)</a>
was extremely easy to setup, and it can run any shell script you want it to. Moreover, adhering to a strict UNIX philosophy, ensures that every new thing that I add can extend existing tools leading to even better workflows.</p>
<p>On my system, I tend not to use GUI programs because often they lack features that I need, or it's just faster to do it on the command line. Most tasks I do on my computer involve writing, editing, or manipulating text, so it doesn't make sense to have 5 different programs to all have to build integrations with each other, when they could all go through a unified interface like the command line or a real extensible editor like <a href=https://www.gnu.org/savannah-checkouts/gnu/emacs/emacs.html>GNU Emacs</a>.</p>
<p>For instance, I recently replaced <a href=https://keepassxc.org>KeePassXC</a>
with the <a href=https://www.passwordstore.org>unix password-store (pass)</a>
utility. While KeePassXC was enjoyable in GUI heavy workflows, the program tries to write to the readonly file in the Nix store, which causes some problems customizing the program. Not wanting to touch a massive codebase and keep up with security patches, I opted for a simpler utility that <em>just works</em>
and I haven't had much problem with password-store. It even does <a href=https://codeberg.org/PassFF/passff>browser autofill</a>, and <a href=https://github.com/tadfisher/pass-otp>OTP codes!</a></p>
<h4 id="nixos-vs-openbsd">NixOS vs OpenBSD</h4>
<p>My utmost concern, when it comes to operating systems, is that they must be reliable enough that I can leave them in the background, and they will do their thing, forever unchanging, until I change them. In essence, I want to be able to trust my computer is working for me, not someone else.</p>
<p>In my experience, there are two reasonable ways to solve this problem: Either lockfile everything down and be fully reproducible <b>OR</b>
be extremely stable and have a dedicated first party way of doing things</p>
<p>This lead me to explore two different operating systems which take these two routes, and discover the subtle needs that warrant the right tool for job (which could be different depending on the circumstances).</p>
<h5 id="nixos-as-a-desktop">NixOS as a Desktop</h5>
<p>A desktop PC needs to run a graphical display; play audio, and games; easily add and remove new software; and more. I've omitted obvious stuff like security and performance, since these should be givens, not a feature. For this application, I think that NixOS is clearly the winner because of better compatibility support and the ability to quickly hop into a <code>nix shell 'nixpkgs#program-here'</code>
and start tinkering with a new package. Moreover, the ability to rollback to a working configuration in this volatile environment is extremely handy.</p>
<h5 id="nixos-as-a-server">NixOS as a Server</h5>
<p>As a server, NixOS is also great because there are so many different programs and services that can be easily setup such as <a href=https://www.mankier.com/8/nfsd>nfs</a>, <a href=https://git-scm.com/book/en/v2/Git-on-the-Server-Git-Daemon>git daemon</a>, <a href=https://soju.im>Soju IRC bouncer</a>, firewall, and more! It's very simple to enable a service and configure it how you like, and be able to reproduce that configuration on another machine with one command.</p>
<p>That being said, there are occasional issues with SystemD isolation causing certain services to be unable to access a file or other program which involves some debugging and ugly fixes. Though the benefits definitely far outweigh the problems when it comes to this approach.</p>
<h5 id="openbsd">OpenBSD</h5>
<p><a href=https://www.openbsd.org>OpenBSD</a>
approaches this problem from a different perspective by prioritizing correctness, good documentation, and having builtin ways of doing things. The first thing I noticed when I setup an OpenBSD VPS to host my static site and do TLS termination, was the great man pages and solid library of builtin programs. I use <a href=https://man.openbsd.org/httpd>httpd</a>, and <a href=https://man.openbsd.org/acme-client>acme-client</a>
to handle serving my website html pages and SSL certs. I also use <a href=https://man.openbsd.org/pf>pf</a>
and <a href=https://man.openbsd.org/relayd>relayd</a>
to handle routing different packets to where they need to go, between my homelab and httpd. Overall, the operating system experience is very well thought out, and a breath of fresh air compared to Linux.</p>
<p>OpenBSD is probably the only operating system, I know, that I would trust to touch the public internet.</p>
<ol class="list-disc">
<li>Its core philosophy of correctness and continuous <a href=https://www.openbsd.org/security.html>security</a>
audits keep it secure.</li>
<li>The unified vision ensures that programs work well with each other since they have the same expectations. For example: httpd and relayd can work harmoniously without interfering with each other even though they touch similar areas.</li>
</ol>
<p>So then why don't I use OpenBSD as my desktop OS? Well, I think that's a great question. I am already pretty happy with my current NixOS setup, and it wouldn't be much benefit to switch over to a BSD yet.</p>
<h4 id="the-problems-with-nix">The Problems With Nix</h4>
<ol class="list-disc">
<li><b>Poor Documentation</b>: If you just use basic features then <a href=https://search.nixos.org>search.nixos.org</a>
and <a href=https://mynixos.com>mynixos.com</a>
have got you covered. It's ironic that I have to mention two sources of docs, since the official nixos.org one has great detail, but it's lacking Nix-Darwin options. On the other hand, mynixos.com has better organization, but is missing package sets like <code>emacsPackages</code></li>
<li>The <code>sudo nixos-rebuild switch --flake .</code>
rebuild and evaulation time take more than 10 seconds every time. It's frustrating because you can't get a fast iteration loop to test out small config changes, and I wish they could make it faster.</li>
<li>NixOS depends on SystemD which means that it would be difficult to migrate to a different init system.</li>
<li>Nix store making things read only which causes some programs to break.</li>
<li>Disk bloat which caused problems trying to update my laptop which was running out of disk space.</li>
<li>Not really a Nix problem, but <a href=https://neovim.io>Neovim</a>
tries to be the opposite of suckless by constantly changing and adding new updates/package managers. At the time of writing this, I'm trying out GNU Emacs.</li>
</ol>
<h4 id="conclusion">Conclusion</h4>
<p>Overall, I highly recommend Nix for power users. It has helped me create a reproducible dotfiles configuration, manage & survey all the programs I installed on my computer, and have an easy to change, yet stable operating system.</p>
<p>After using NixOS for a year, I'm still figuring out some of the more advanced features of the language:</p>
<ol class="list-disc">
<li>Modules, and whether they are really worth hiding away parts of my code for reuse as my configuration.nix gets longer.</li>
<li>Where to draw the lines between where certain configuration should live.</li>
<li>What is configuration and what is data that should stay out of Nix.</li>
</ol>
<hr>
</article>
</main>
<footer class="main-footer">
<p>Return to <a href="#top">top?</a></p>
<p><a href="https://skullheadx.com">https://skullheadx.com</a></p>
</footer>
</div>
</body>
</html>
|