diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index ef3c2d674..82626809e 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -304,6 +304,9 @@
 
 /modules/services/taskwarrior-sync.nix                @minijackson @pacien
 
+/modules/services/trayer.nix                          @AndreasMager
+/tests/modules/services/trayer                        @AndreasMager
+
 /modules/services/udiskie.nix                         @rycee
 
 /modules/services/unison.nix                          @pacien
diff --git a/modules/lib/maintainers.nix b/modules/lib/maintainers.nix
index d091b28a4..2f14dbef1 100644
--- a/modules/lib/maintainers.nix
+++ b/modules/lib/maintainers.nix
@@ -115,4 +115,10 @@
     githubId = 56614642;
     name = "Ilan Joselevich";
   };
+  mager = {
+    email = "andreas@mager.eu";
+    github = "AndreasMager";
+    githubId = 5646732;
+    name = "Andreas Mager";
+  };
 }
diff --git a/modules/misc/news.nix b/modules/misc/news.nix
index 02286d2f3..bda956fab 100644
--- a/modules/misc/news.nix
+++ b/modules/misc/news.nix
@@ -2141,6 +2141,13 @@ in
         '';
       }
 
+      {
+        time = "2021-07-23T22:22:31+00:00";
+        condition = hostPlatform.isLinux;
+        message = ''
+          A new module is available: 'services.trayer'.
+        '';
+      }
     ];
   };
 }
diff --git a/modules/modules.nix b/modules/modules.nix
index e92cc6fdc..6114c2425 100644
--- a/modules/modules.nix
+++ b/modules/modules.nix
@@ -206,6 +206,7 @@ let
     ./services/sxhkd.nix
     ./services/syncthing.nix
     ./services/taffybar.nix
+    ./services/trayer.nix
     ./services/tahoe-lafs.nix
     ./services/taskwarrior-sync.nix
     ./services/udiskie.nix
diff --git a/modules/services/trayer.nix b/modules/services/trayer.nix
new file mode 100644
index 000000000..6b5da31ce
--- /dev/null
+++ b/modules/services/trayer.nix
@@ -0,0 +1,183 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+  boolTrue = {
+    type = types.bool;
+    values = "true|false";
+    default = "true";
+  };
+
+  number0 = {
+    type = types.int;
+    values = "number";
+    default = "0";
+  };
+
+  knownSettings = {
+    edge = {
+      type = types.str;
+      values = "left|right|top|bottom|none";
+      default = "bottom";
+    };
+
+    align = {
+      type = types.str;
+      values = "left|right|center";
+      default = "center";
+    };
+
+    margin = number0;
+    widthtype = {
+      type = types.str;
+      values = "request|pixel|percent";
+      default = "percent";
+    };
+
+    width = {
+      type = types.int;
+      values = "number";
+      default = "100";
+    };
+
+    heighttype = {
+      type = types.str;
+      values = "request|pixel";
+      default = "pixel";
+    };
+
+    height = {
+      type = types.int;
+      values = "number";
+      default = "26";
+    };
+
+    SetDockType = boolTrue;
+
+    SetPartialStrut = boolTrue;
+
+    transparent = {
+      type = types.bool;
+      values = "true|false";
+      default = "false";
+    };
+
+    alpha = {
+      type = types.int;
+      values = "number";
+      default = "127";
+    };
+
+    tint = {
+      type = types.str;
+      values = "int";
+      default = "0xFFFFFFFF";
+    };
+
+    distance = number0;
+
+    distancefrom = {
+      type = types.str;
+      values = "left|right|top|bottom";
+      default = "top";
+    };
+
+    expand = boolTrue;
+
+    padding = number0;
+
+    monitor = {
+      values = "number|primary";
+      type = types.str;
+      default = "0";
+    };
+
+    iconspacing = number0;
+  };
+
+  cfg = config.services.trayer;
+
+in {
+  meta.maintainers = [ maintainers.mager ];
+
+  options = {
+    services.trayer = {
+      enable = mkEnableOption
+        "trayer, the lightweight GTK2+ systray for UNIX desktops";
+
+      package = mkOption {
+        default = pkgs.trayer;
+        defaultText = literalExample "pkgs.trayer";
+        type = types.package;
+        example = literalExample "pkgs.trayer";
+        description = "The package to use for the trayer binary.";
+      };
+
+      settings = mkOption {
+        type = with types; attrsOf (nullOr (either str (either bool int)));
+        description = ''
+          Trayer configuration as a set of attributes. Further details can be
+          found at <link xlink:href="https://github.com/sargon/trayer-srg"/>.
+
+          <informaltable frame="none"><tgroup cols="4">
+          <thead>
+          <row>
+          <entry>Property Name</entry>
+          <entry>Type</entry>
+          <entry>Values</entry>
+          <entry>Default</entry>
+          </row>
+          </thead><tbody>
+          ${concatStringsSep "\n" (mapAttrsToList (n: v: ''
+            <row>
+              <entry><varname>${n}</varname></entry>
+              <entry>${v.type.description}</entry>
+              <entry>${v.values}</entry>
+              <entry>${v.default}</entry>
+            </row>
+          '') knownSettings)}
+          </tbody></tgroup></informaltable>
+        '';
+        default = { };
+        example = literalExample ''
+          {
+            edge = "top";
+            padding = 6;
+            SetDockType = true;
+            tint = "0x282c34";
+          }
+        '';
+      };
+    };
+  };
+
+  config = mkIf cfg.enable ({
+    assertions = [
+      (lib.hm.assertions.assertPlatform "services.trayer" pkgs
+        lib.platforms.linux)
+    ];
+
+    home.packages = [ cfg.package ];
+
+    systemd.user.services.trayer = let
+      valueToString = v:
+        if isBool v then (if v then "true" else "false") else "${toString v}";
+      parameter = k: v: "--${k} ${valueToString v}";
+      parameters = concatStringsSep " " (mapAttrsToList parameter cfg.settings);
+    in {
+      Unit = {
+        Description = "trayer -- lightweight GTK2+ systray for UNIX desktops";
+        PartOf = [ "tray.target" ];
+      };
+
+      Install.WantedBy = [ "tray.target" ];
+
+      Service = {
+        ExecStart = "${cfg.package}/bin/trayer ${parameters}";
+        Restart = "on-failure";
+      };
+    };
+  });
+}
diff --git a/tests/default.nix b/tests/default.nix
index 670c45a2b..e71e1fd8a 100644
--- a/tests/default.nix
+++ b/tests/default.nix
@@ -128,6 +128,7 @@ import nmt {
     ./modules/services/redshift-gammastep
     ./modules/services/sxhkd
     ./modules/services/syncthing
+    ./modules/services/trayer
     ./modules/services/window-managers/bspwm
     ./modules/services/window-managers/i3
     ./modules/services/window-managers/sway
diff --git a/tests/modules/services/trayer/basic-configuration.nix b/tests/modules/services/trayer/basic-configuration.nix
new file mode 100644
index 000000000..23632331e
--- /dev/null
+++ b/tests/modules/services/trayer/basic-configuration.nix
@@ -0,0 +1,29 @@
+{ config, pkgs, ... }:
+
+{
+  config = {
+    services.trayer = {
+      enable = true;
+      package = pkgs.writeScriptBin "dummy-trayer" "" // {
+        outPath = "@trayer@";
+      };
+      settings = {
+        edge = "top";
+        padding = 6;
+        SetDockType = true;
+        tint = "0x282c34";
+        SetPartialStrut = true;
+        expand = true;
+        monitor = 1;
+      };
+    };
+
+    nmt.script = ''
+      serviceFile=home-files/.config/systemd/user/trayer.service
+
+      assertFileExists $serviceFile
+      assertFileContains $serviceFile \
+        'ExecStart=@trayer@/bin/trayer --SetDockType true --SetPartialStrut true --edge top --expand true --monitor 1 --padding 6 --tint 0x282c34'
+    '';
+  };
+}
diff --git a/tests/modules/services/trayer/default.nix b/tests/modules/services/trayer/default.nix
new file mode 100644
index 000000000..f8672b59e
--- /dev/null
+++ b/tests/modules/services/trayer/default.nix
@@ -0,0 +1 @@
+{ trayer-basic-configuration = ./basic-configuration.nix; }