diff --git a/modules/default.nix b/modules/default.nix
index 1c569ef6b..a9d3552f2 100644
--- a/modules/default.nix
+++ b/modules/default.nix
@@ -30,6 +30,7 @@ let
     ./programs/htop.nix
     ./programs/info.nix
     ./programs/lesspipe.nix
+    ./programs/rofi.nix
     ./programs/ssh.nix
     ./programs/termite.nix
     ./programs/texlive.nix
diff --git a/modules/misc/news.nix b/modules/misc/news.nix
index 70b320d2a..db2aee347 100644
--- a/modules/misc/news.nix
+++ b/modules/misc/news.nix
@@ -232,6 +232,12 @@ in
           tool in that NIX_AUTO_INSTALL is not supported.
         '';
       }
+      {
+        time = "2017-09-28T12:39:36+00:00";
+        message = ''
+          A new program module is available: 'programs.rofi';
+        '';
+      }
     ];
   };
 }
diff --git a/modules/programs/rofi.nix b/modules/programs/rofi.nix
new file mode 100644
index 000000000..0194a3d56
--- /dev/null
+++ b/modules/programs/rofi.nix
@@ -0,0 +1,260 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+with builtins;
+
+let
+
+  cfg = config.programs.rofi;
+
+  colorOption = description: mkOption {
+    type = types.string;
+    description = description;
+  };
+
+  rowColorSubmodule = types.submodule {
+    options = {
+      background = colorOption "Background color";
+      foreground = colorOption "Foreground color";
+      backgroundAlt = colorOption "Alternative background color";
+      highlight = mkOption {
+        type = types.submodule {
+          options = {
+            background = colorOption "Highlight background color";
+            foreground = colorOption "Highlight foreground color";
+          };
+        };
+        description = "Color settings for highlighted row.";
+      };
+    };
+  };
+
+  windowColorSubmodule = types.submodule {
+    options = {
+      background = colorOption "Window background color";
+      border = colorOption "Window border color";
+      separator = colorOption "Separator color";
+    };
+  };
+
+  colorsSubmodule = types.submodule {
+    options = {
+      window = mkOption {
+        default = null;
+        type = windowColorSubmodule;
+        description = "Window color settings.";
+      };
+      rows = mkOption {
+        default = null;
+        type = types.submodule {
+          options = {
+            normal = mkOption {
+              default = null;
+              type = types.nullOr rowColorSubmodule;
+              description = "Normal row color settings.";
+            };
+            active = mkOption {
+              default = null;
+              type = types.nullOr rowColorSubmodule;
+              description = "Active row color settings.";
+            };
+            urgent = mkOption {
+              default = null;
+              type = types.nullOr rowColorSubmodule;
+              description = "Urgent row color settings.";
+            };
+          };
+        };
+        description = "Rows color settings.";
+      };
+    };
+  };
+
+  valueToString = value:
+    if isBool value
+      then (if value then "true" else "else")
+      else toString value;
+
+  windowColorsToString = window: concatStringsSep ", " (with window; [
+    background
+    border
+    separator
+  ]);
+
+  rowsColorsToString = rows: ''
+    ${optionalString
+        (rows.normal != null)
+        (setOption "color-normal" (rowColorsToString rows.normal))}
+    ${optionalString
+        (rows.active != null)
+        (setOption "color-active" (rowColorsToString rows.active))}
+    ${optionalString
+        (rows.urgent != null)
+        (setOption "color-urgent" (rowColorsToString rows.urgent))}
+  '';
+
+  rowColorsToString = row: concatStringsSep ", " (with row; [
+    background
+    foreground
+    backgroundAlt
+    highlight.background
+    highlight.foreground
+  ]);
+
+  setOption = name: value:
+    optionalString (value != null) "rofi.${name}: ${valueToString value}";
+
+  setColorScheme = colors: optionalString (colors != null) ''
+    ${optionalString
+        (colors.window != null)
+        setOption "color-window" (windowColorsToString colors.window)}
+    ${optionalString
+        (colors.rows != null)
+        (rowsColorsToString colors.rows)}
+  '';
+
+in
+
+{
+  options.programs.rofi = {
+    enable = mkEnableOption "Rofi: A window switcher, application launcher and dmenu replacement";
+
+    width = mkOption {
+      default = null;
+      type = types.nullOr types.int;
+      description = "Window width";
+      example = 100;
+    };
+
+    lines = mkOption {
+      default = null;
+      type = types.nullOr types.int;
+      description = "Number of lines";
+      example = 10;
+    };
+
+    borderWidth = mkOption {
+      default = null;
+      type = types.nullOr types.int;
+      description = "Border width";
+      example = 1;
+    };
+
+    rowHeight = mkOption {
+      default = null;
+      type = types.nullOr types.int;
+      description = "Row height (in chars)";
+      example = 1;
+    };
+
+    padding = mkOption {
+      default = null;
+      type = types.nullOr types.int;
+      description = "Padding";
+      example = 400;
+    };
+
+    font = mkOption {
+      default = null;
+      type = types.nullOr types.string;
+      example = "Droid Sans Mono 14";
+      description = "Font to use";
+    };
+
+    scrollbar = mkOption {
+      default = null;
+      type = types.nullOr types.bool;
+      description = "Whether to show a scrollbar.";
+    };
+
+    terminal = mkOption {
+      default = null;
+      type = types.nullOr types.string;
+      description = ''
+        Path to the terminal which will be used to run console applications
+      '';
+      example = "\${pkgs.gnome3.gnome_terminal}/bin/gnome-terminal";
+    };
+
+    separator = mkOption {
+      default = null;
+      type = types.nullOr (types.enum [ "none" "dash" "solid" ]);
+      description = "Separator style";
+      example = "solid";
+    };
+
+    cycle = mkOption {
+      default = null;
+      type = types.nullOr types.bool;
+      description = "Whether to cycle through the results list";
+    };
+
+    colors = mkOption {
+      default = null;
+      type = types.nullOr colorsSubmodule;
+      description = ''
+        Color scheme settings.
+        Colors can be specified in CSS color formats.
+      '';
+      example = literalExample ''
+        colors = {
+          window = {
+            background = "argb:583a4c54";
+            border = "argb:582a373e";
+            separator = "#c3c6c8";
+          };
+
+          rows = {
+            normal = {
+              background = "argb:58455a64";
+              foreground = "#fafbfc";
+              backgroundAlt = "argb:58455a64";
+              highlight = {
+                background = "#00bcd4";
+                foreground = "#fafbfc";
+              };
+            };
+          };
+        };
+      '';
+    };
+
+    configPath = mkOption {
+      default = ".config/rofi/config";
+      type = types.string;
+      description = "Path where to put generated configuration file.";
+    };
+
+    extraConfig = mkOption {
+      default = "";
+      type = types.lines;
+      description = "Additional configuration to add.";
+    };
+
+  };
+
+  config = mkIf cfg.enable {
+    home.packages = [ pkgs.rofi ];
+
+    home.file."${cfg.configPath}".text = ''
+      ${setOption "width" cfg.width}
+      ${setOption "lines" cfg.lines}
+      ${setOption "font" cfg.font}
+      ${setOption "bw" cfg.borderWidth}
+      ${setOption "eh" cfg.rowHeight}
+      ${setOption "padding" cfg.padding}
+      ${setOption "separator-style" cfg.separator}
+      ${setOption "hide-scrollbar" (
+        if (cfg.scrollbar != null)
+        then (! cfg.scrollbar)
+        else cfg.scrollbar
+      )}
+      ${setOption "terminal" cfg.terminal}
+      ${setOption "cycle" cfg.cycle}
+
+      ${setColorScheme cfg.colors}
+
+      ${cfg.extraConfig}
+    '';
+  };
+}