diff --git a/lib/builders.nix b/lib/builders.nix
deleted file mode 100644
index 7127ad9f..00000000
--- a/lib/builders.nix
+++ /dev/null
@@ -1,71 +0,0 @@
-{ pkgs, lib, self }:
-
-{
-  /* Create an XDG MIME Association listing. This should also take care of
-     generating desktop-specific mimeapps.list if `desktopName` is given. The
-     given desktop name is already assumed to be in suitable casing which is
-     typically in lowercase ASCII.
-  */
-  makeXDGMimeAssociationList = {
-    desktopName ? "",
-    addedAssociations ? { },
-    removedAssociations ? { },
-    defaultApplications ? { },
-  }:
-    pkgs.writeTextFile {
-      name = "xdg-mime-associations${lib.optionalString (desktopName != "") "-${desktopName}"}";
-      text =
-        # Non-desktop-specific mimeapps.list are only allowed to specify
-        # default applications.
-        lib.generators.toINI { } ({
-          "Default Applications" = defaultApplications;
-        } // (lib.optionalAttrs (desktopName == "") {
-          "Added Associations" = addedAssociations;
-          "Removed Associations" = removedAssociations;
-        }));
-      destination = "/share/applications/${lib.optionalString (desktopName != "") "${desktopName}-"}mimeapps.list";
-    };
-
-  /* Create an XDG Portals configuration with the given desktop name and its
-     configuration. Similarly, the given desktop name is assumed to be already
-     in its suitable form of a lowercase ASCII.
-  */
-  makeXDGPortalConfiguration = {
-    desktopName ? "common",
-    config,
-  }:
-    pkgs.writeTextFile {
-      name = "xdg-portal-config${lib.optionalString (desktopName != "common") "-${desktopName}"}";
-      text = lib.generators.toINI { } config;
-      destination = "/share/xdg-desktop-portal/${lib.optionalString (desktopName != "common") "${desktopName}-"}portals.conf";
-    };
-
-  /* Create an XDG desktop entry file. Unlike the `makeDesktopItem`, it doesn't
-     have a required schema as long as it is valid data to be converted to.
-     Furthermore, the validation process can be disabled in case you want to
-     create something like an entry for a desktop session.
-  */
-  makeXDGDesktopEntry = {
-    name,
-    config,
-    validate ? true,
-    destination ? "/share/applications/${name}.desktop",
-  }:
-    pkgs.writeTextFile {
-      name = "xdg-desktop-entry-${name}";
-      text = lib.generators.toINI {
-        listsAsDuplicateKeys = false;
-        mkKeyValue = lib.generators.mkKeyValueDefault {
-          mkValueString = v:
-            if lib.isList v then lib.concatStringsSep ";" v
-            else lib.generators.mkValueStringDefault { } v;
-        } "=";
-      } config;
-      inherit destination;
-      checkPhase =
-        lib.optionalString validate
-          ''
-            ${lib.getExe' pkgs.desktop-file-utils "desktop-file-validate"} "$target"
-          '';
-    };
-}
diff --git a/lib/builders/default.nix b/lib/builders/default.nix
new file mode 100644
index 00000000..77cf3822
--- /dev/null
+++ b/lib/builders/default.nix
@@ -0,0 +1,7 @@
+{ pkgs, lib, self }:
+
+{
+  makeXDGMimeAssociationList = pkgs.callPackage ./xdg/make-association-list.nix { };
+  makeXDGPortalConfiguration = pkgs.callPackage ./xdg/make-portal-config.nix { };
+  makeXDGDesktopEntry = pkgs.callPackage ./xdg/make-desktop-entry.nix { };
+}
diff --git a/lib/builders/xdg/make-association-list.nix b/lib/builders/xdg/make-association-list.nix
new file mode 100644
index 00000000..588b9997
--- /dev/null
+++ b/lib/builders/xdg/make-association-list.nix
@@ -0,0 +1,38 @@
+{ lib, writeTextFile }:
+
+/* Create an XDG MIME Association listing. This should also take care of
+   generating desktop-specific mimeapps.list if `desktopName` is given. The
+   given desktop name is already assumed to be in suitable casing which is
+   typically in lowercase ASCII.
+*/
+{
+  # An optional string containing the name of the desktop to be associated
+  # with.
+  desktopName ? "",
+
+  # Applications to be put in `Added Associations`. This is not set when the
+  # database is desktop-specific (when the `desktopName` is non-empty.)
+  addedAssociations ? { },
+
+  # Associations to be put in `Removed Associations` in the file. Similar to
+  # `addedAssociations`, this will not be added when it is desktop-specific.
+  removedAssociations ? { },
+
+  # Set of applications to be opened associated with the MIME type.
+  defaultApplications ? { },
+}:
+
+writeTextFile {
+  name = "xdg-mime-associations${lib.optionalString (desktopName != "") "-${desktopName}"}";
+  text =
+    # Non-desktop-specific mimeapps.list are only allowed to specify
+    # default applications.
+    lib.generators.toINI { } ({
+      "Default Applications" = defaultApplications;
+    } // (lib.optionalAttrs (desktopName == "") {
+      "Added Associations" = addedAssociations;
+      "Removed Associations" = removedAssociations;
+    }));
+  destination = "/share/applications/${lib.optionalString (desktopName != "") "${desktopName}-"}mimeapps.list";
+}
+
diff --git a/lib/builders/xdg/make-desktop-entry.nix b/lib/builders/xdg/make-desktop-entry.nix
new file mode 100644
index 00000000..a2448764
--- /dev/null
+++ b/lib/builders/xdg/make-desktop-entry.nix
@@ -0,0 +1,39 @@
+{ lib, writeTextFile, desktop-file-utils }:
+
+/* Create an XDG desktop entry file. Unlike the `makeDesktopItem`, it doesn't
+   have a required schema as long as it is valid data to be converted to.
+   Furthermore, the validation process can be disabled in case you want to
+   create something like an entry for a desktop session.
+*/
+{
+  # Name of the desktop entry. Only used as part of the package name and the
+  # default value of the destination path.
+  name,
+
+  # Nix-representable data to be exported as the desktop entry.
+  config,
+
+  # Add a validation check for the exported desktop entry.
+  validate ? true,
+
+  # Destination path relative to the output path.
+  destination ? "/share/applications/${name}.desktop",
+}:
+
+writeTextFile {
+  name = "xdg-desktop-entry-${name}";
+  text = lib.generators.toINI {
+    listsAsDuplicateKeys = false;
+    mkKeyValue = lib.generators.mkKeyValueDefault {
+      mkValueString = v:
+        if lib.isList v then lib.concatStringsSep ";" v
+        else lib.generators.mkValueStringDefault { } v;
+    } "=";
+  } config;
+  inherit destination;
+  checkPhase =
+    lib.optionalString validate
+      ''
+        ${lib.getExe' desktop-file-utils "desktop-file-validate"} "$target"
+      '';
+}
diff --git a/lib/builders/xdg/make-portal-config.nix b/lib/builders/xdg/make-portal-config.nix
new file mode 100644
index 00000000..7a0eff78
--- /dev/null
+++ b/lib/builders/xdg/make-portal-config.nix
@@ -0,0 +1,17 @@
+{ lib, writeTextFile }:
+
+/* Create an XDG Portals configuration with the given desktop name and its
+ configuration. Similarly, the given desktop name is assumed to be already
+ in its suitable form of a lowercase ASCII.
+*/
+{
+  desktopName ? "common",
+
+  # Nix-representable data to be exported as the portal configuration.
+  config,
+}:
+writeTextFile {
+  name = "xdg-portal-config${lib.optionalString (desktopName != "common") "-${desktopName}"}";
+  text = lib.generators.toINI { } config;
+  destination = "/share/xdg-desktop-portal/${lib.optionalString (desktopName != "common") "${desktopName}-"}portals.conf";
+}
diff --git a/lib/default.nix b/lib/default.nix
index 5b003684..cd258c7d 100644
--- a/lib/default.nix
+++ b/lib/default.nix
@@ -14,7 +14,7 @@ pkgs.lib.makeExtensible
   let
     callLib = file: import file { inherit pkgs lib self; };
   in {
-    builders = callLib ./builders.nix;
+    builders = callLib ./builders;
     trivial = callLib ./trivial.nix;
     data = callLib ./data.nix;
     fetchers = callLib ./fetchers;