Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

NixOS Configuration

If you are using NixOS, configuring greetd to use mdgreet is straightforward. You can define everything declaratively in your configuration files.

While cage is a common choice for greeters, it has limitations with multi-monitor setups (e.g., determining which exact monitor displays the greeter).

Using niri is highly recommended. It allows you to strictly define the output monitor, force fullscreen mode, and disable keybindings so users cannot accidentally close the greeter or interact with the compositor.

Here is an example configuration using niri:

{ config, pkgs, lib, ... }:

let
  mdgreetPkg = pkgs.mdgreet;
  
  # 1. Define your mdgreet configuration
  mdgreetConfig = {
    appearance = {
      greeting = "Welcome to NixOS!";
      theme.mode = "dark";
      theme.seed_color = "#89b4fa"; # Catppuccin Mocha Blue
    };
  };

  # 2. Define the niri configuration specifically for the greeter
  niriConfig = pkgs.writeText "niri-greet.kdl" ''
    // Specify the target monitor (replace DP-1 with your actual monitor name)
    // You can find monitor names by running `niri msg outputs` in a normal session.
    output "DP-1" {
      focus-at-startup
      layout {
        // Match the background color to your mdgreet theme to avoid flashes
        background-color "#1e1e2e"
      }
    }

    // Disable all hotkeys so the user cannot close the greeter or interact with niri
    hotkey-overlay { skip-at-startup; }

    window-rule {
      match at-startup=true
      open-fullscreen true
    }

    // Launch mdgreet and exit niri when mdgreet is done
    spawn-sh-at-startup "${lib.getExe mdgreetPkg} ; ${lib.getExe pkgs.niri} msg action quit --skip-confirmation"
  '';
in
{
  # Generate the TOML configuration file
  environment.etc."greetd/mdgreet.toml".source =
    (pkgs.formats.toml {}).generate "mdgreet.toml" mdgreetConfig;

  # Make sure greetd has the necessary directories
  systemd.tmpfiles.settings."10-mdgreet" = {
    "/var/cache/mdgreet".d = { mode = "0755"; user = "greeter"; group = "greeter"; };
    "/var/log/mdgreet".d =   { mode = "0755"; user = "greeter"; group = "greeter"; };
  };

  # Configure the greetd service
  services.greetd = {
    enable = true;
    settings = {
      default_session = {
        # Launch niri with our custom config
        command = "${lib.getExe pkgs.niri} --config ${niriConfig}";
        user = "greeter";
      };
    };
  };
  
  # Ensure necessary packages are available
  environment.systemPackages = with pkgs; [ niri dbus ];
}

Alternative: Using cage (Single monitor)

If you have a single monitor or don’t mind the greeter appearing on the default screen, you can use cage. It’s a kiosk compositor designed to run a single full-screen application.

{ config, pkgs, ... }:

let
  mdgreetPkg = pkgs.mdgreet;
  mdgreetConfig = {
    appearance = { greeting = "Welcome!"; }
  };
in
{
  environment.etc."greetd/mdgreet.toml".source =
    (pkgs.formats.toml {}).generate "mdgreet.toml" mdgreetConfig;

  systemd.tmpfiles.settings."10-mdgreet" = {
    "/var/cache/mdgreet".d = { mode = "0755"; user = "greeter"; group = "greeter"; };
    "/var/log/mdgreet".d =   { mode = "0755"; user = "greeter"; group = "greeter"; };
  };

  services.greetd = {
    enable = true;
    settings = {
      default_session = {
        # -s ensures it runs smoothly via systemd
        command = "${pkgs.cage}/bin/cage -s -- ${mdgreetPkg}/bin/mdgreet";
        user = "greeter";
      };
    };
  };

  environment.systemPackages = with pkgs; [ cage dbus ];
}