TIL: Setting default browser on macOS using Nix

Let’s say you’ve just switched browser. If you’re a normal person, the new browser will probably ask you whether you want to change your default browser. You’ll click the little button and it’ll happen. Or you go into System Preferences and do it.

Now you can stop reading. But if you’re weird and want to set it programatically on macOS, here’s a hacky way to do it using Nix-Darwin.

It uses defaultbrowser, which is a teeny little CLI tool that calls the relevant Objective-C functions.

If you run defaultbrowser without an argument, it shows you what browsers you have installed. You then pass one of those browser identifier strings to it as an argument.

Some options for known browsers: safari, chrome, firefox, librewolf, torbrowser.

Now let’s put it in a Nix-Darwin setup.

let
   vars = {
     # ...
     defaultbrowser = "librewolf";
   };
in # ... your nix-darwin setup

defaultbrowser needs to be installed as a system package, so let’s add it to environment.systemPackages

  environment.systemPackages = import ./modules/packages.nix pkgs
    ++ (if (vars ? "defaultbrowser" && builtins.isString vars.defaultbrowser) then [ pkgs.defaultbrowser ] else [ ]);

Now we need an activation script that’ll run it every time you run your Nix setup (which will be relatively often).

  system.activationScripts = (if (vars ? "defaultbrowser" && builtins.isString vars.defaultbrowser) then {
    postUserActivation.text = "defaultbrowser ${vars.defaultbrowser}";
  } else { });

defaultbrowser is clever enough that if you tell it to set your default browser to one that already is your default browser, it’ll just print a nice message to the screen like:

librewolf is already set as the default HTTP handler

I thought about adding the variable to the list of packages (or Homebrew Casks, or Mac App Store apps) that need installing, but there’s a mismatch between the browser identifier string and the package name used by nixpkgs and/or Homebrew. Plus if you’re using Safari, there’s kind of no way to not install it. So you need to make sure you’ve installed the browser, and check the browser identifier string with defaultbrowser.

Warning: this is and hacky, and far from perfect (I know enough Nix to be vaguely useful but not enough to do it right). Maybe this functionality could be built into nix-darwin. An enterprising hacker could write some code that uses this in Nix-Darwin, and uses xdg.mimeApps.defaultApplications on Linux.