Customizing Firefox with Nix and Home Manager — Hugo Sum

Customizing Firefox with Nix and Home Manager

In this post I will share my experience on customizing Firefox using Nix and Home Manager, so you can easily create reproducible and declarative configuration to manage your Firefox.

Installing Firefox with Home Manager

Installing Firefox with Home Manager is easy on Linux, just set programs.firefox.enable = true and you are good to go.

# ./home-manager/firefox.nix
{ inputs, lib, config, pkgs, ... }: {
  programs.firefox = {
    enable = true;
  };
}

However, if you are using Home Manager on MacOS, you will find out that the firefox package is broken on darwin. Luckily, there is a nixpkgs-firefox-darwin overlay that provides a firefox derivation that works on darwin. Browsers derived from firefox, such as librewolf and floorp are also supported by this overlay.

To use this overlay, add this flake as an input to your flake, and pass the nixpkgs-firefox-darwin.overlay to overlays in the import statement of nixpkgs.

{
  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/release-24.11";

    home-manager.url = "github:nix-community/home-manager/release-24.11";
    home-manager.inputs.nixpkgs.follows = "nixpkgs";

    nixpkgs-firefox-darwin.url =
      "github:bandithedoge/nixpkgs-firefox-darwin";
    nixpkgs-firefox-darwin.inputs.nixpkgs.follows = "nixpkgs";
  };

  outputs = { self, nixpkgs, home-manager, nixpkgs-firefox-darwin, ... }@inputs:
    let
      inherit (self) outputs;
      lib = nixpkgs.lib;
      darwinArmSystem = "aarch64-darwin";

      darwinArmPkgs = import nixpkgs {
        system = darwinArmSystem;
        overlays = [
          nixpkgs-firefox-darwin.overlay # add the overlay from the input
        ];
      };
    in {
      homeConfigurations = {
        "darwin" = home-manager.lib.homeManagerConfiguration {
          pkgs = darwinArmPkgs;
          modules = [ ./home-manager/firefox.nix ];
        };
      };
    };
}

Configuring Firefox with Home Manager

To configure options avaliable to Firefox in about:config editor with Home Manager, you can create a profile with programs.firefox.profiles.<name> and define options specific to this profile at programs.firefox.profiles.<name>.settings.

# ./home-manager/firefox.nix
{ inputs, lib, config, pkgs, ... }: {
  programs.firefox = {
    enable = true;
    profiles = {
      admin = {
        id = 0;
        name = "admin";
        isDefault = true;
        settings = {
          "extensions.pocket.enabled" = false;
          "browser.toolbarbuttons.introduced.pocket-button" = false;
        };
      };
    };
  };
}

I have tried to find an exhaustive list for all options in about:config, but based on this conversation that seems to be non-existent.

Installing Firefox extensions with Home Manager

Firefox extensions are not packaged in the official nixpkgs repository but in the nur repository. To use this repository, you have to include it as an input for a flake, and apply an overlay in the import statement of nixpkgs.

# flake.nix
{
  inputs = {
    # omitted for brevity

    nur.url = "github:nix-community/NUR/master";
    nur.inputs.nixpkgs.follows = "nixpkgs";
  };

  outputs = { self, nixpkgs, home-manager, nixpkgs-firefox-darwin, nur, ... }@inputs:
    let
      inherit (self) outputs;
      lib = nixpkgs.lib;
      darwinArmSystem = "aarch64-darwin";

      darwinArmPkgs = import nixpkgs {
        system = darwinArmSystem;
        overlays = [
          nixpkgs-firefox-darwin.overlay
          nur.overlays.default # add the overlay from the input
        ];
      };
    in {
      # omitted for brevity
    };
}

After applying the overlay, we can then include Firefox extensions as packages at programs.firefox.profiles.<name>.extensions.

# ./home-manager/firefox.nix
{ inputs, lib, config, pkgs, ... }: {
  programs.firefox = {
    enable = true;
    profiles = {
      admin = {
        id = 0;
        name = "admin";
        isDefault = true;
        extensions = with pkgs; [
          # installing bitwarden and ublock-origin through nur
          nur.repos.rycee.firefox-addons.bitwarden
          nur.repos.rycee.firefox-addons.ublock-origin
        ];
      };
    };
  };
}

When I was configuring my own flake, after doing the above, I thought I have done everything I need to set up extensions in Firefox. However, I found out that programs.firefox.profiles.<name>.extensions would only install but not enable the extensions for you.

Enable Firefox extensions with policies.json

Firefox allows users to customize its functionality with policies.json. Skimming through the available options, I notice that we can force an extension to be enabled with Extensions.Locked. This unobvious option is exactly what we need.

Extensions.Locked is an array that accepts the ID of a Firefox extension. You can find out the ID of your extensions in about:debugging#/runtime/this-firefox.

Another useful option is ExtensionSettings, which allow you to customize where to show the extension, for example pinning it to the navbar. There are a lot more you can do with policies.json, I highly recommend you go through the documentation.

The corresponding Home Manager option to manage policies.json is programs.firefox.policies.

{ inputs, lib, config, pkgs, ... }: {
  programs.firefox = {
    enable = true;
    policies = {
      Extensions = {
        Locked = [
          # enable both extensions
          "uBlock0@raymondhill.net"
          "446900e4-71c2-419f-a6a7-df9c091e268b" # Extension ID for bitwarden
        ];
      };
      ExtensionSettings = {
        # pin both extensions in the navbar
        "uBlock0@raymondhill.net" = { default_area = "navbar"; };
        "446900e4-71c2-419f-a6a7-df9c091e268b" = { default_area = "navbar"; };
      };
    };
    # omitted for brevity
  };
}

Defining custom search engines and its shortcut alias

To define custom search engines and its shortcut alias in Firefox with Home Manager, you can define them at programs.firefox.profiles.<name>.search.engines. The following is my definition that allows me to search packages in https://search.nixos.org/packages after typing a shortcut alias of @nix.

{ inputs, lib, config, pkgs, system, isDarwin, ... }: {
  programs.firefox = {
    # omitted for brevity
    profiles = {
      admin = {
        search = {
          engines = {
            "Nix Packages" = {
              urls = [{
                template = "https://search.nixos.org/packages";
                params = [
                  {
                    name = "type";
                    value = "packages";
                  }
                  {
                    name = "query";
                    value = "{searchTerms}";
                  }
                ];
              }];

              icon =
                "${pkgs.nixos-icons}/share/icons/hicolor/scalable/apps/nix-snowflake.svg";
              definedAliases = [ "@nix" ];
            };
          };
        };
      };
    };
  };
}

Hugo Sum

A Hongkonger living in the UK. The only thing I know is there is so much I don't know.

Archive