<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>chukwuanu</title>
    <subtitle>Notes on building systems that work and other things... maybe?</subtitle>
    <link rel="self" type="application/atom+xml" href="https://chukwuanu.com/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://chukwuanu.com"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-01-17T00:00:00+00:00</updated>
    <id>https://chukwuanu.com/atom.xml</id>
    <entry xml:lang="en">
        <title>A year of Nix on macOS</title>
        <published>2026-01-17T00:00:00+00:00</published>
        <updated>2026-01-17T00:00:00+00:00</updated>
        
        <author>
          <name>
            
              Unknown
            
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://chukwuanu.com/p/nix-on-macos/"/>
        <id>https://chukwuanu.com/p/nix-on-macos/</id>
        
        <content type="html" xml:base="https://chukwuanu.com/p/nix-on-macos/">&lt;p&gt;I remember the exact moment I decided to try Nix. It was a Thursday night, somewhere around 11pm, and I was staring at a broken terminal after a macOS update had silently reset my dock preferences, broken three Homebrew symlinks, and somehow changed my default Python. Again. I&#x27;d been maintaining my dotfiles since January 2021 (vim plugins, zsh themes, git configs, the whole ritual) and every few months something would just... stop working. No clear reason. Just vibes.&lt;&#x2F;p&gt;
&lt;p&gt;So on January 17, 2025, I added a &lt;code&gt;flake.nix&lt;&#x2F;code&gt; to my dotfiles repo. I had no idea what I was doing.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-before-times&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-before-times&quot; aria-label=&quot;Anchor link for: the-before-times&quot;&gt;The before times&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Let me paint the picture of what I had. A &lt;code&gt;.zshrc&lt;&#x2F;code&gt; that had grown organically over four years. A Brewfile that was mostly accurate. An &lt;code&gt;install.sh&lt;&#x2F;code&gt; that I wrote once, ran once, and never touched again because I was afraid of what it would do. Config files scattered across &lt;code&gt;~&#x2F;.config&#x2F;&lt;&#x2F;code&gt; with no clear record of which ones I&#x27;d manually edited and which ones came from the repo.&lt;&#x2F;p&gt;
&lt;p&gt;The setup &lt;em&gt;worked&lt;&#x2F;em&gt;. I could write code, push commits, deploy services. But every time I needed to set up a new machine or debug a broken path, I&#x27;d spend half a day reading my own shell history to figure out what I&#x27;d done six months ago.&lt;&#x2F;p&gt;
&lt;p&gt;The worst part was the terminal emulator situation. I&#x27;d gone from Alacritty to Kitty to Ghostty, and each migration left behind config files, PATH entries, and font caches that I&#x27;d forget about until they caused some weird conflict.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;finding-nix&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#finding-nix&quot; aria-label=&quot;Anchor link for: finding-nix&quot;&gt;Finding Nix&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Nix is one of those tools that everyone describes differently. &quot;It&#x27;s a package manager.&quot; &quot;It&#x27;s a build system.&quot; &quot;It&#x27;s a functional programming language for system configuration.&quot; All of these are technically true and none of them helped me understand why I should care.&lt;&#x2F;p&gt;
&lt;p&gt;What finally clicked was this: Nix lets you describe what your system should look like, and then it makes it look like that. Change the description, it computes the diff. Break something, roll back. Nothing else to it.&lt;&#x2F;p&gt;
&lt;p&gt;On macOS, &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;LnL7&#x2F;nix-darwin&quot;&gt;nix-darwin&lt;&#x2F;a&gt; extends this to system-level stuff (Homebrew packages, macOS defaults, keyboard mappings, firewall rules) and &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;nix-community&#x2F;home-manager&quot;&gt;Home Manager&lt;&#x2F;a&gt; handles the user-level things (dotfiles, shell aliases, environment variables).&lt;&#x2F;p&gt;
&lt;p&gt;My system is now two files and a Makefile. &lt;code&gt;flake.nix&lt;&#x2F;code&gt; for the system. &lt;code&gt;home.nix&lt;&#x2F;code&gt; for my user environment. &lt;code&gt;make rebuild&lt;&#x2F;code&gt; to apply everything. No install script. No manual steps. No &quot;did I remember to run that command.&quot;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;how-it-actually-happened&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#how-it-actually-happened&quot; aria-label=&quot;Anchor link for: how-it-actually-happened&quot;&gt;How it actually happened&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;It wasn&#x27;t instant. Looking back through my git history, I can trace exactly how it unfolded.&lt;&#x2F;p&gt;
&lt;p&gt;The first &lt;code&gt;flake.nix&lt;&#x2F;code&gt; in January 2025 was cautious. I just moved a few packages in: &lt;code&gt;neovim&lt;&#x2F;code&gt;, &lt;code&gt;ripgrep&lt;&#x2F;code&gt;, &lt;code&gt;jq&lt;&#x2F;code&gt;, &lt;code&gt;rustup&lt;&#x2F;code&gt;. I also added &lt;code&gt;nil&lt;&#x2F;code&gt; (the Nix language server) and &lt;code&gt;nixfmt&lt;&#x2F;code&gt; because editing Nix files without tooling is like writing Rust without rust-analyzer. Technically possible, practically miserable.&lt;&#x2F;p&gt;
&lt;p&gt;Two months later I added Home Manager, and that was the moment everything changed. Before, I was symlinking config files with a shell script and crossing my fingers. Now I could just declare them:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#E1E4E8, #E1E4E8); background-color: light-dark(#24292E, #24292E);&quot;&gt;&lt;code data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#FFAB70, #FFAB70);&quot;&gt;home&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#FFAB70, #FFAB70);&quot;&gt;file&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt;.config&#x2F;ghostty&#x2F;config&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#FFAB70, #FFAB70);&quot;&gt;source&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#FDAEB7, #FDAEB7);font-style: italic;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt; .&#x2F;config&#x2F;ghostty&#x2F;config&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#FDAEB7, #FDAEB7);font-style: italic;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#FFAB70, #FFAB70);&quot;&gt;home&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#FFAB70, #FFAB70);&quot;&gt;file&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt;.config&#x2F;git&#x2F;config&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#FFAB70, #FFAB70);&quot;&gt;source&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#FDAEB7, #FDAEB7);font-style: italic;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt; .&#x2F;config&#x2F;git&#x2F;config&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#FDAEB7, #FDAEB7);font-style: italic;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#FFAB70, #FFAB70);&quot;&gt;home&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#FFAB70, #FFAB70);&quot;&gt;file&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt;.config&#x2F;zed&#x2F;settings.json&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#FFAB70, #FFAB70);&quot;&gt;source&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#FDAEB7, #FDAEB7);font-style: italic;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt; .&#x2F;config&#x2F;zed&#x2F;settings.json&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#FDAEB7, #FDAEB7);font-style: italic;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Change the source file, run &lt;code&gt;make rebuild&lt;&#x2F;code&gt;, the symlink updates. No &lt;code&gt;ln -sf&lt;&#x2F;code&gt;. No checking if the target exists. No cleanup of stale links from three terminal emulators ago.&lt;&#x2F;p&gt;
&lt;p&gt;Then in May I made a mistake. I tried to manage Homebrew entirely through Nix using a thing called &lt;code&gt;nix-homebrew&lt;&#x2F;code&gt;. The idea was beautiful: one system to rule them all. The reality was fragile. Homebrew really wants to own its own state. Taps, cask tokens, update cycles. It has opinions about these things, and fighting those opinions was causing more problems than it solved.&lt;&#x2F;p&gt;
&lt;p&gt;So I ripped it out. Instead, I let nix-darwin manage Homebrew &lt;em&gt;declaratively&lt;&#x2F;em&gt; without trying to &lt;em&gt;replace&lt;&#x2F;em&gt; it:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#E1E4E8, #E1E4E8); background-color: light-dark(#24292E, #24292E);&quot;&gt;&lt;code data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#FFAB70, #FFAB70);&quot;&gt;homebrew&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#FDAEB7, #FDAEB7);font-style: italic;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B392F0, #B392F0);&quot;&gt;  enable&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#79B8FF, #79B8FF);&quot;&gt; true&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B392F0, #B392F0);&quot;&gt;  onActivation&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B392F0, #B392F0);&quot;&gt;cleanup&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt;zap&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B392F0, #B392F0);&quot;&gt;  onActivation&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B392F0, #B392F0);&quot;&gt;autoUpdate&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#79B8FF, #79B8FF);&quot;&gt; true&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B392F0, #B392F0);&quot;&gt;  onActivation&lt;&#x2F;span&gt;&lt;span&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#B392F0, #B392F0);&quot;&gt;upgrade&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#79B8FF, #79B8FF);&quot;&gt; true&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B392F0, #B392F0);&quot;&gt;  brews&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt;go&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt;gh&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt;lazygit&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt;grpcurl&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt; .&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt; ]&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B392F0, #B392F0);&quot;&gt;  casks&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt;ghostty&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt;zed&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt;docker-desktop&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt; .&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt; ]&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#FDAEB7, #FDAEB7);font-style: italic;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;That &lt;code&gt;onActivation.cleanup = &quot;zap&quot;&lt;&#x2F;code&gt; line is the important one. It means: if a package is not in this list, remove it. The flake becomes the source of truth. If you &lt;code&gt;brew install&lt;&#x2F;code&gt; something manually, it gets removed on the next rebuild. This forces you to declare everything. At first it felt annoying. Then it felt liberating.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-path-weekend&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-path-weekend&quot; aria-label=&quot;Anchor link for: the-path-weekend&quot;&gt;The PATH weekend&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;This one deserves its own section because it took longer than I&#x27;d like to admit.&lt;&#x2F;p&gt;
&lt;p&gt;Nix and Homebrew both want to control what&#x27;s on your PATH. The Nix daemon needs to be sourced before anything else, but Homebrew&#x27;s &lt;code&gt;shellenv&lt;&#x2F;code&gt; also modifies PATH. Get the ordering wrong and you end up running the system &lt;code&gt;git&lt;&#x2F;code&gt; instead of Homebrew&#x27;s, or the Homebrew &lt;code&gt;python&lt;&#x2F;code&gt; instead of &lt;code&gt;pyenv&lt;&#x2F;code&gt;&#x27;s. I spent a lot of time staring at &lt;code&gt;echo $PATH&lt;&#x2F;code&gt; output before I landed on this:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#E1E4E8, #E1E4E8); background-color: light-dark(#24292E, #24292E);&quot;&gt;&lt;code data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#FFAB70, #FFAB70);&quot;&gt;programs&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#FFAB70, #FFAB70);&quot;&gt;zsh&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#FFAB70, #FFAB70);&quot;&gt;shellInit&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#FDAEB7, #FDAEB7);font-style: italic;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt; &amp;#39;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt;  if [ -e &amp;#39;&#x2F;nix&#x2F;var&#x2F;nix&#x2F;profiles&#x2F;default&#x2F;etc&#x2F;profile.d&#x2F;nix-daemon.sh&amp;#39; ]; then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt;    . &amp;#39;&#x2F;nix&#x2F;var&#x2F;nix&#x2F;profiles&#x2F;default&#x2F;etc&#x2F;profile.d&#x2F;nix-daemon.sh&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt;  fi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt;  export PATH=&amp;quot;&#x2F;run&#x2F;current-system&#x2F;sw&#x2F;bin:&#x2F;nix&#x2F;var&#x2F;nix&#x2F;profiles&#x2F;default&#x2F;bin:$PATH&amp;quot;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt;&amp;#39;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#FDAEB7, #FDAEB7);font-style: italic;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Nix paths first, then Homebrew via &lt;code&gt;shellenv&lt;&#x2F;code&gt;, then user paths. Simple in retrospect. Not simple at 2am.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;where-it-got-fun&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#where-it-got-fun&quot; aria-label=&quot;Anchor link for: where-it-got-fun&quot;&gt;Where it got fun&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Once the foundation was solid, I started pulling in everything I used to configure manually. Keyboard remapping in early 2026 (Caps Lock to Escape, because life is too short for Caps Lock). File associations with &lt;code&gt;duti&lt;&#x2F;code&gt; shortly after (Zed as default editor for 38 file types). And the one that made me irrationally happy: macOS defaults.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#E1E4E8, #E1E4E8); background-color: light-dark(#24292E, #24292E);&quot;&gt;&lt;code data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#FFAB70, #FFAB70);&quot;&gt;system&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#FFAB70, #FFAB70);&quot;&gt;defaults&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#FDAEB7, #FDAEB7);font-style: italic;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B392F0, #B392F0);&quot;&gt;  dock&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B392F0, #B392F0);&quot;&gt;    autohide&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#79B8FF, #79B8FF);&quot;&gt; true&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B392F0, #B392F0);&quot;&gt;    autohide-delay&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#79B8FF, #79B8FF);&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#79B8FF, #79B8FF);&quot;&gt;0&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B392F0, #B392F0);&quot;&gt;    autohide-time-modifier&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#79B8FF, #79B8FF);&quot;&gt; 0&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#79B8FF, #79B8FF);&quot;&gt;15&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B392F0, #B392F0);&quot;&gt;    show-recents&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#79B8FF, #79B8FF);&quot;&gt; false&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B392F0, #B392F0);&quot;&gt;    tilesize&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#79B8FF, #79B8FF);&quot;&gt; 60&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B392F0, #B392F0);&quot;&gt;  NSGlobalDomain&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B392F0, #B392F0);&quot;&gt;    AppleInterfaceStyle&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt;Dark&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B392F0, #B392F0);&quot;&gt;    InitialKeyRepeat&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#79B8FF, #79B8FF);&quot;&gt; 14&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B392F0, #B392F0);&quot;&gt;    KeyRepeat&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#79B8FF, #79B8FF);&quot;&gt; 1&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B392F0, #B392F0);&quot;&gt;    ApplePressAndHoldEnabled&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#79B8FF, #79B8FF);&quot;&gt; false&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B392F0, #B392F0);&quot;&gt;    NSAutomaticCapitalizationEnabled&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#79B8FF, #79B8FF);&quot;&gt; false&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B392F0, #B392F0);&quot;&gt;    NSAutomaticSpellingCorrectionEnabled&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#79B8FF, #79B8FF);&quot;&gt; false&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  }&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#FDAEB7, #FDAEB7);font-style: italic;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;My dock animation speed used to get reset every macOS update. I&#x27;d forget, notice it three days later, Google the &lt;code&gt;defaults write&lt;&#x2F;code&gt; command, run it, forget it again. Now &lt;code&gt;make rebuild&lt;&#x2F;code&gt; handles it. Forever.&lt;&#x2F;p&gt;
&lt;p&gt;Security went in too. Firewall with stealth mode, Touch ID for sudo, GPG signing on all commits. All in the flake, all reproducible.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#E1E4E8, #E1E4E8); background-color: light-dark(#24292E, #24292E);&quot;&gt;&lt;code data-lang=&quot;nix&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#FFAB70, #FFAB70);&quot;&gt;networking&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#FFAB70, #FFAB70);&quot;&gt;applicationFirewall&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#FDAEB7, #FDAEB7);font-style: italic;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B392F0, #B392F0);&quot;&gt;  enable&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#79B8FF, #79B8FF);&quot;&gt; true&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B392F0, #B392F0);&quot;&gt;  enableStealthMode&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#79B8FF, #79B8FF);&quot;&gt; true&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;}&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#FDAEB7, #FDAEB7);font-style: italic;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#FFAB70, #FFAB70);&quot;&gt;security&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#FFAB70, #FFAB70);&quot;&gt;pam&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#FFAB70, #FFAB70);&quot;&gt;services&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#FFAB70, #FFAB70);&quot;&gt;sudo_local&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#FFAB70, #FFAB70);&quot;&gt;touchIdAuth&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#FDAEB7, #FDAEB7);font-style: italic;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#79B8FF, #79B8FF);&quot;&gt; true&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#FDAEB7, #FDAEB7);font-style: italic;&quot;&gt;;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;&lt;h2 id=&quot;the-daemon-problem&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-daemon-problem&quot; aria-label=&quot;Anchor link for: the-daemon-problem&quot;&gt;The daemon problem&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;I need to be honest about this because no one else seems to talk about it: the Nix daemon on macOS is flaky. After system updates, sleep&#x2F;wake cycles, or sometimes for no apparent reason, it just stops responding. &lt;code&gt;nix-store --version&lt;&#x2F;code&gt; hangs. Everything breaks.&lt;&#x2F;p&gt;
&lt;p&gt;I got tired of debugging this manually, so I wrote a script that handles both Determinate Systems and standard Nix installations:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color-scheme: light dark; color: light-dark(#E1E4E8, #E1E4E8); background-color: light-dark(#24292E, #24292E);&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt;if&lt;&#x2F;span&gt;&lt;span&gt; [&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt; -f&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt;&#x2F;Library&#x2F;LaunchDaemons&#x2F;systems.determinate.nix-store.plist&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt; ]&lt;&#x2F;span&gt;&lt;span&gt;;&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt; then&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B392F0, #B392F0);&quot;&gt;    sudo&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt; launchctl&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt; bootout&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt; system&#x2F;systems.determinate.nix-store&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B392F0, #B392F0);&quot;&gt;    sudo&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt; launchctl&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt; bootstrap&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt; system&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt; &#x2F;Library&#x2F;LaunchDaemons&#x2F;systems.determinate.nix-store.plist&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#B392F0, #B392F0);&quot;&gt;    sudo&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt; launchctl&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt; bootstrap&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt; system&lt;&#x2F;span&gt;&lt;span style=&quot;color: light-dark(#9ECBFF, #9ECBFF);&quot;&gt; &#x2F;Library&#x2F;LaunchDaemons&#x2F;systems.determinate.nix-daemon.plist&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: light-dark(#F97583, #F97583);&quot;&gt;fi&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The Makefile runs this before every rebuild. It adds about a second. Worth it to never think about the daemon again.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-homebrew-boundary&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#the-homebrew-boundary&quot; aria-label=&quot;Anchor link for: the-homebrew-boundary&quot;&gt;The Homebrew boundary&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;After a year of trial and error, I learned something I wish someone had told me upfront: don&#x27;t try to replace Homebrew. Just control it.&lt;&#x2F;p&gt;
&lt;p&gt;Nix is great for pure binaries that work identically on any platform. &lt;code&gt;neovim&lt;&#x2F;code&gt;, &lt;code&gt;ripgrep&lt;&#x2F;code&gt;, &lt;code&gt;jq&lt;&#x2F;code&gt;, &lt;code&gt;tree-sitter&lt;&#x2F;code&gt;. But the moment you need something with macOS-specific compilation (like &lt;code&gt;postgresql@18&lt;&#x2F;code&gt;) or a GUI app (like Ghostty or Zed), Homebrew is just better at it. Fighting that boundary wastes time. The &lt;code&gt;onActivation.cleanup = &quot;zap&quot;&lt;&#x2F;code&gt; pattern is the right answer. Let Homebrew be Homebrew. Just make sure the flake decides what it installs.&lt;&#x2F;p&gt;
&lt;p&gt;I wasted weeks learning this the hard way. You don&#x27;t have to.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;one-year-later&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#one-year-later&quot; aria-label=&quot;Anchor link for: one-year-later&quot;&gt;One year later&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;My dotfiles repo started in January 2021 with vim plugins and a zshrc. Five years later it&#x27;s a complete, declarative system specification. I&#x27;ve used &lt;code&gt;make rebuild&lt;&#x2F;code&gt; to set up a fresh Mac. Took under 20 minutes, most of that just waiting for downloads.&lt;&#x2F;p&gt;
&lt;p&gt;But honestly, the fresh install scenario almost never happens. The real win is smaller and more frequent. A macOS update breaks something? Rebuild. New project needs a tool? One line, rebuild. Regret it? Rollback. Every change is a commit. Every state is recoverable.&lt;&#x2F;p&gt;
&lt;p&gt;That&#x27;s what Nix gives you. Not magic. Just a system that remembers what it&#x27;s supposed to look like, even when you don&#x27;t.&lt;&#x2F;p&gt;
</content>
        
    </entry>
</feed>
