{
lib,
config,
pkgs,
...
}:
let
cfg = config.mjm.desktop;
in
{
imports = [
./autologin.nix
./boot.nix
./chrysalis.nix
./firefox.nix
./fonts.nix
./games.nix
./network.nix
./niri.nix
./plasma.nix
./sound.nix
./ssh.nix
./ssh-tpm.nix
./virtualisation.nix
];
options.mjm.desktop = {
enable = lib.mkEnableOption "desktop environment";
};
config = lib.mkIf cfg.enable {
<<config>>
};
_class = "nixos";
}I have three different NixOS workstations, and they all use the same overall configuration for their desktops. It's big enough to be broken down into several submodules.
=> autologin
=> firefox
=> games
=> network
=> niri
=> ssh
=> ssh-tpm
TODO document the other submodules
The options set here in the main file are kind of a grab bag of small things that don't make sense to split into other files.
mjm.helix.enable = lib.mkDefault true;
My desktop machines also automatically enable my module for the Helix text editor.
documentation.enable = true;
In the base module, I disable documentation to save space and build time. But it's useful, so I reenable it on workstations.
time.timeZone = "America/Denver";
Workstations should show the local time rather than UTC.
It would probably make sense to set this to null on laptops, since they can move between time zones. Setting the time zone imperatively might make more sense there.
mjm.deploy.targetHost = lib.mkOverride 900 null;
Workstations should be excluded from automated deploys, which is done by setting their target host to null. The override makes it take precedence over mkDefault, but still be lower priority than a normal setting of the option.
services.displayManager.plasma-login-manager.enable = true;
Regardless of desktop environment or compositor, I am using plasma-login-manager as the display manager. It's the evolution of sddm, and based on my experience it is the least janky one. In particular, NixOS does some pretty weird things to set up gdm, so I'm avoiding that.
services.displayManager.hiddenUsers = [ "matt" ];
When I first set up several of my machines, I used the username "matt", but now I use "mjm" across the board. Because I'm using userborn to set up users and groups, deleting a user once it is created is not trivial. This old user is inactive, but without this configuration, it will still show up in login prompts.
systemd.oomd = {
enableRootSlice = true;
enableUserSlices = true;
};systemd-oomd is enabled by default on NixOS, but it doesn't take action unless you configure slices to act based on memory pressure. These options enable the same defaults Fedora uses, which will kill processes in the root slice and user slices when they exceed 80% memory pressure for 20 seconds.
hardware.bluetooth.enable = true; services.blueman.enable = true;
All of my workstations are capable of using Bluetooth (uranus needs a dongle) so enable it across the board.
services.printing.enable = true; services.system-config-printer.enable = true; services.avahi.enable = true;
Much to my dismay, there is in fact a printer in my home. It's an evil thing, but when it wants to cooperate, it is nice to be able to use it.
programs.kdeconnect.enable = true;
It's nice to be able to use KDE Connect to get notifications from my phone or send text messages from my computer. Installing the package also configures the kdeconnectd backend service to autostart with the desktop session.
services.udev.extraRules = ''
ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="046d", ATTRS{idProduct}=="c24a", ATTR{power/wakeup}="enabled"
'';For some reason, the Logitech G600 mouse that I use when gaming isn't able to wake up the system by default. I don't have this problem with my Kinesis Advantage 2 keyboard or my Kensington Trackball, which are my primary peripherals at my desk. Maybe it's connected to the wrong port or something. This udev rule fixes the issue. I keep it in the desktop module in the event that I ever plug another machine into the displays at my desk.
programs.nix-ld.enable = true;
nix-ld makes it possible to run binaries on NixOS that expect libraries to be in more normal FHS locations. I avoided it for a long time, but eventually caved due to issues with compiling Zed extensions that this fixes.
boot.binfmt.emulatedSystems =
let
inherit (pkgs.stdenv.hostPlatform) system;
in
lib.mkMerge [
(lib.mkIf (system == "x86_64-linux") [ "aarch64-linux" ])
(lib.mkIf (system == "aarch64-linux") [ "x86_64-linux" ])
];It's really easy to make a NixOS machine be able to build and run binaries for another architecture. It uses qemu-user, which means it's by no means fast, but it can be useful in a pinch, especially when you manage machines for multiple architectures. Since I have both x86_64 and aarch64 machines, I configure my workstations to emulate whichever architecture they are not.
environment.systemPackages = lib.attrValues {
inherit (pkgs)
bitwarden-desktop
element-desktop
jellyfin-mpv-shim
krita
lagrange
mpv
# radicle-desktop
signal-desktop
strawberry
wl-clipboard
xclip
xdg-utils
yt-dlp
zeal
;
inherit (pkgs.kdePackages)
ark
filelight
kcalc
ktorrent
okular
plasmatube
;
homestuck = lib.mkIf pkgs.stdenv.hostPlatform.isx86_64 pkgs.unofficial-homestuck-collection;
};These are miscellaneous packages that are installed on all of my desktop machines.
environment.etc."yt-dlp/plugins/bgutil-ytdlp-pot-provider/yt_dlp_plugins".source =
"${pkgs.python314Packages.bgutil-ytdlp-pot-provider}/lib/python3.14/site-packages/yt_dlp_plugins";
environment.etc."yt-dlp/config".text = ''
-v
-t mkv
--extractor-args youtubepot-bgutilscript:server_home=${pkgs.python314Packages.bgutil-ytdlp-pot-provider}/share/bgutil-ytdlp-pot-provider
--cookies-from-browser=firefox
'';This yt-dlp plugin helps avoid issues downloading videos from YouTube, which I like to do sometimes for archival purposes.
environment.etc."mpv/mpv.conf".text = '' video-sync = display-resample profile = high-quality '';
I have some basic configuration for mpv which I sometimes use to watch videos.
environment.etc."xdg/user-dirs.defaults".text = '' DESKTOP=desktop DOCUMENTS=documents DOWNLOAD=downloads PICTURES=pictures PROJECTS=src '';
I prefer to make some customizations to the default XDG user dirs. I remove some of the directories that I don't personally use, and others are lowercased or (in the case of Projects) renamed.
text/gemini;lang=en-USThis content has been proxied by September (UNKNO).