
Intro
Nixos is not your regular distro. Its "immutable" and "reproducible" and all that, things that most the of arch linux elites ignore before jumping into the nixos hype train. Instead of configuring your programs through ~/.config/appname
files, we do it through .nix
files. Instead of starting and stopping services with systemctl
, we do it through .nix
files. Instead of installing programs via a package manager, we do it through, you guessed it, .nix
files. Most of the linux youtubers and average users do not fully explore nixos before going back to their old distro. They just configure their stuff in a big and ugly configuration.nix
file. This blog will try to get you working hyprland
on a flake
powered nixos setup.
Basic Nix Commands
- Rebuilding Nix System
1$ sudo nixos-rebuild switch
2# with flakes
3$ sudo nixos-rebuild switch --flake '/etc/nixos#frostbyte'
- Rebuilding Home Directory
1$ home-manager switch
2
3# with flakes
4$ home-manager switch --flake '/etc/nixos#namish' # replace namish with your user
- Updating nix flake inputs
1$ nix flake update
Flakes
A nix flake is a directory with a flake.nix
and flake.lock
that returns Nix expressions that can be used to install packages, run programs or in out case, create a whole ass NixOs configuration. Each flake consists of two parts defined in the flake.nix
, inputs
and outputs
-
Inputs:
inputs
are the equivalent of dependencies. They are the external resources or Flakes that a particular Flake needs to accomplish its tasks -
Outpus:
outputs
refer to the different results or artifacts that a Flake can produce when it's built or evaluated. Think of them as the things that a Flake can create or provide. In this case it provides us with a nixos configuration
Why flakes?
NixOS Flakes is a feature that enhances the Nix package manager's capabilities by providing a structured and reproducible way to define and manage software packages and system configurations. It promotes consistency, immutability, and composability, making it particularly valuable for system administrators and developers who need to manage complex and reliable computing environments
Enabling Flakes
Currently flakes is a beta experimental feature that we have to manually enable
1{ pkgs, ... }: {
2 nix.settings.experimental-features = [ "nix-command" "flakes" ];
3}
Then rebuild system with sudo nixos-rebuild switch
Basic Flake
01{
02 description = "i have no idea how this works";
03
04 inputs = {
05 # Package sources.
06 master.url = "github:nixos/nixpkgs/master";
07 stable.url = "github:nixos/nixpkgs/nixos-22.11";
08 unstable.url = "github:nixos/nixpkgs/nixos-unstable";
09 home-manager.url = "github:nix-community/home-manager";
10 nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
11 hyprland.url = "github:hyprwm/Hyprland";
12 spicetify-nix.url = "github:the-argus/spicetify-nix";
13 nixpkgs-f2k.url = "github:fortuneteller2k/nixpkgs-f2k";
14 hyprland-plugins.url = "github:hyprwm/hyprland-plugins";
15
16 # Channel to follow.
17 home-manager.inputs.nixpkgs.follows = "unstable";
18 nixpkgs.follows = "unstable";
19 };
20 outputs = { self, nixpkgs, home-manager, hyprland, hyprland-plugins, ... } @inputs:
21 let
22 inherit (self) outputs;
23 forSystems = nixpkgs.lib.genAttrs nixpkgs.lib.systems.flakeExposed;
24 system = "x86_64-linux";
25 pkgs = import nixpkgs {
26 inherit system;
27 };
28 in
29 {
30 # host configurations
31 nixosConfigurations = {
32 frostbyte = nixpkgs.lib.nixosSystem
33 {
34 specialArgs = {
35 inherit inputs outputs home-manager hyprland hyprland-plugins;
36 };
37 modules = [
38 # > Our main nixos configuration file <
39 home-manager.nixosModule
40 ./hosts/frostbyte/configuration.nix
41 ];
42 };
43 };
44 home-manager = home-manager.packages.${nixpkgs.system}."home-manager";
45 # user configurations
46 homeConfigurations = {
47 namish = home-manager.lib.homeManagerConfiguration {
48 pkgs = nixpkgs.legacyPackages.x86_64-linux; # Home-manager requires 'pkgs' instance
49 extraSpecialArgs = { inherit inputs outputs home-manager self; };
50 modules = [
51 ./home/namish/home.nix
52 ];
53 };
54 };
55 frostbyte = self.nixosConfigurations.frostbyte.config.system.build.toplevel;
56 };
57}
58
Now of course this will not work, we still have to configure home manager and our system. Be sure to replace namish
with your username.
Deriviations and overlays
This section is very important to understand. These two topics are really important to install programs that are not in the nix repos. In our config derivs will be placed at ./derivs
and overlays are at ./overlays/default.nix
Deriviations
At a basic level, deriviations are just a way to build packages on your system. The structure of a Nix derivation is a set of specifications and instructions that define how to build and package a software component within the Nix package management system
Common Pieces of a nix deriviation:
- Name and Version: A derivation typically starts with specifying the name and version of the software component you want to package.
1name = "example";
2version = "1.0";
- Source: You specify the source code or binary of the software you're packaging. This could be from a
tar
,github repo
, aurl
or even local files
1 src = fetchFromGitHub {
2 owner = "ozwaldorf";
3 repo = "lutgen-rs";
4 rev = "621db41b10e5a1a923ef67094ce1fc05c618d6ae";
5 sha256 = "0dwj3cksf62z89ihqnhhxj1wgzjqqwlc40hwdfw18yqwr3byzfxf";
6 };
- Build Process: This section outlines the steps to compile and build the software. You specify how to configure, compile, and install the software
1buildPhase = ''
2 make
3'';
4
5installPhase = ''
6 make install
7'';
- Dependencies: You declare the dependencies required to build and run the software. Nix will ensure that these dependencies are available during the build process
1buildInputs = with pkgs;[ gcc autoconf ];
- Meta Info: You can include metadata about the package, such as its description and license information.
1meta = with lib; {
2 description = "An example software package";
3 license = licenses.mit;
4};
Example Deriviations
01{ lib, buildPythonPackage, fetchFromGitHub, pkgs, ... }\:
02
03buildPythonPackage rec {
04 pname = "imagecolorizer";
05 version = "git";
06 preBuild = ''
07 cat > setup.py << EOF
08 from setuptools import setup
09 setup(
10 name='ImageColorizer',
11 version='1.2',
12 packages=['ImageColorizer'],
13 entry_points = {
14 'console_scripts': ['ImageColorizer = ImageColorizer.__main__:main']
15 }
16 )
17 EOF
18 '';
19 propagatedBuildInputs = with pkgs;[
20 python310Packages.pillow
21 ];
22 src = fetchFromGitHub {
23 repo = "ImageColorizer";
24 owner = "kiddae";
25 rev = "48623031e3106261093723cd536a4dae74309c5d";
26 sha256 = "0ai4i3qmk55z3zc2gd8nicgx04pmfxl5wcq43ryy6l4c6gj2ik5r";
27 };
28 meta = {
29 description = "ImageColorizer is a Python module and a CLI tool that you can easily use to colorize wallpapers for them to fit a terminal colorscheme.";
30 homepage = "https://github.com/kiddae/ImageColorizer";
31 license = lib.licenses.mit;
32 platforms = lib.platforms.unix;
33 };
34}
35
01{ lib, fetchFromGitHub, rustPlatform, pkgs }:
02rustPlatform.buildRustPackage rec {
03 pname = "lutgen";
04 name = "lutgen";
05
06 src = fetchFromGitHub {
07 owner = "ozwaldorf";
08 repo = "lutgen-rs";
09 rev = "621db41b10e5a1a923ef67094ce1fc05c618d6ae";
10 sha256 = "0dwj3cksf62z89ihqnhhxj1wgzjqqwlc40hwdfw18yqwr3byzfxf";
11 };
12 nativeBuildInputs = with pkgs;[
13 cargo
14 rustc
15 ];
16 cargoSha256 = "sha256-s5ejGEFMxDg+ENLg0Y1ZXgk2bDyy4H5C7tNMjVEp8kY=";
17}
Overlays
Nix overlays are a mechanism in the Nix package manager that allows you to extend or modify the package set provided by the Nixpkgs repository. They are a way to add, replace, or customize packages and configurations without altering the global Nixpkgs repository. For example to use a custom fork of st we can make an overlay like this
01{ inputs }:
02{
03 additions = final: _prev: import ../pkgs { pkgs = final; inherit inputs; };
04 modifications = final: prev: {
05 # WE WILL ADD OUR OVERLAYS HERE
06 st = prev.st.overrideAttrs (oldAttrs: {
07 buildInputs = oldAttrs.buildInputs ++ [ prev.harfbuzz ];
08 src = prev.fetchFromGitHub {
09 owner = "chadcat7";
10 repo = "st";
11 rev = "3d9eb51d43981963638a1b5a8a6aa1ace4b90fbb";
12 sha256 = "007pvimfpnmjz72is4y4g9a0vpq4sl1w6n9sdjq2xb2igys2jsyg";
13 };
14 });
15 };
16}
For this to work, you need ./nixpkgs.nix
and ./pkgs/default.nix
1# A nixpkgs instance that is grabbed from the pinned nixpkgs commit in the lock file
2# This is useful to avoid using channels when using legacy nix commands
3let lock = (builtins.fromJSON (builtins.readFile ./flake.lock)).nodes.nixpkgs.locked;
4in
5import (fetchTarball {
6 url = "https://github.com/nixos-unstable/nixpkgs/archive/${lock.rev}.tar.gz";
7 sha256 = lock.narHash;
8})
9
1# Custom packages, that can be defined similarly to ones from nixpkgs
2# You can build them using 'nix build .#example' or (legacy) 'nix-build -A example'
3{ pkgs ? (import ../nixpkgs.nix) { }, inputs }: {
4 # example = pkgs.callPackage ./example { };
5}
We can even use our deriviations to create an overlay
1 modifications = final: prev: {
2 imgclr = prev.callPackage ../derivs/imagecolorizer.nix {
3 buildPythonPackage = prev.python310Packages.buildPythonPackage;
4 };
5 lutgen = prev.callPackage ../derivs/lutgen.nix { };
6 };
Some more examples
01{ lib, buildPythonPackage, fetchFromGitHub, pkgs, ... }:
02
03buildPythonPackage rec {
04 pname = "imagecolorizer";
05 version = "git";
06 preBuild = ''
07 cat > setup.py << EOF
08 from setuptools import setup
09 setup(
10 name='ImageColorizer',
11 version='1.2',
12 packages=['ImageColorizer'],
13 entry_points = {
14 'console_scripts': ['ImageColorizer = ImageColorizer.__main__:main']
15 }
16 )
17 EOF
18 '';
19 propagatedBuildInputs = with pkgs;[
20 python310Packages.pillow
21 ];
22 src = fetchFromGitHub {
23 repo = "ImageColorizer";
24 owner = "kiddae";
25 rev = "48623031e3106261093723cd536a4dae74309c5d";
26 sha256 = "0ai4i3qmk55z3zc2gd8nicgx04pmfxl5wcq43ryy6l4c6gj2ik5r";
27 };
28 meta = {
29 description = "ImageColorizer is a Python module and a CLI tool that you can easily use to colorize wallpapers for them to fit a terminal colorscheme.";
30 homepage = "https://github.com/kiddae/ImageColorizer";
31 license = lib.licenses.mit;
32 platforms = lib.platforms.unix;
33 };
34}
01{ lib, fetchFromGitHub, rustPlatform, pkgs }:
02rustPlatform.buildRustPackage rec {
03 pname = "lutgen";
04 name = "lutgen";
05
06 src = fetchFromGitHub {
07 owner = "ozwaldorf";
08 repo = "lutgen-rs";
09 rev = "621db41b10e5a1a923ef67094ce1fc05c618d6ae";
10 sha256 = "0dwj3cksf62z89ihqnhhxj1wgzjqqwlc40hwdfw18yqwr3byzfxf";
11 };
12 nativeBuildInputs = with pkgs;[
13 cargo
14 rustc
15 ];
16 cargoSha256 = "sha256-s5ejGEFMxDg+ENLg0Y1ZXgk2bDyy4H5C7tNMjVEp8kY=";
17}
Configuring the system
First we will make two directories, ./hosts/frostbyte
and ./hosts/shared
. The first one would be for the main system itself and shared would be for setttings that would be common for each system (if you have more than 1 devices)
Also copy your existing hardware-configuration.nix
to ./hosts/frostbyte/hardware-configuration.nix
Shared Settings
This will consist of:
- Setting the timezone
- Enabling network, bluetooth, sudo, polkit
- User Config
- Installing Fonts
- Nix Settings
- Actually Installing the overlays
001{ pkgs, outputs, overlays, lib, inputs, ... }:
002let
003 # DEFINING VARIABLES
004 flake-compat = builtins.fetchTarball "https://github.com/edolstra/flake-compat/archive/master.tar.gz";
005in
006{
007 # USING SYSTEMD-BOOT INSTEAD OF GRUB
008 boot.loader.systemd-boot.enable = true;
009 boot.loader.efi.canTouchEfiVariables = true;
010 boot.loader.efi.efiSysMountPoint = "/boot/efi";
011 programs.zsh.enable = true;
012
013 # REQUIRED TO ENABLE SWAYLOCK TO AUTHENTICATE PASSWORDS
014 security.pam.services.swaylock = {
015 text = ''
016 auth include login
017 '';
018 };
019 networking = {
020 networkmanager.enable = true;
021 firewall.enable = false;
022 };
023 security = {
024 sudo.enable = true;
025 };
026 services.blueman = {
027 enable = true;
028 };
029
030 # SETTING TIME ZONE
031 time = {
032 hardwareClockInLocalTime = true;
033 timeZone = "Asia/Kolkata";
034 };
035 i18n.defaultLocale = "en_US.UTF-8";
036 console = {
037 font = "Lat2-Terminus16";
038 useXkbConfig = true;
039 };
040 users = {
041 users.namish = {
042 isNormalUser = true;
043 extraGroups = [ "wheel" "networkmanager" "audio" "video" "libvirtd" ];
044 packages = with pkgs; [ ];
045 };
046 defaultUserShell = pkgs.zsh;
047 };
048 fonts.packages = with pkgs; [
049 inter
050 dosis
051 rubik
052 ibm-plex
053 (nerdfonts.override { fonts = [ "Iosevka" "CascadiaCode" "JetBrainsMono" ]; })
054 ];
055 # STILL USING PULSEAUDIO (SOWWY)
056 sound.enable = true;
057 hardware.pulseaudio.enable = true;
058 hardware.pulseaudio.extraConfig = "load-module module-native-protocol-tcp auth-ip-acl=127.0.0.1";
059 security.rtkit.enable = true;
060 virtualisation = {
061 libvirtd.enable = true;
062 };
063 services.dbus.enable = true;
064 xdg.portal = {
065 enable = true;
066 wlr.enable = true;
067 # gtk portal needed to make gtk apps happy
068 extraPortals = [ pkgs.xdg-desktop-portal-gtk ];
069 };
070
071 environment.systemPackages = with pkgs; [
072 nodejs
073 lutgen
074 home-manager
075 blueman
076 inotify-tools
077 udiskie
078 rnix-lsp
079 xorg.xwininfo
080 pulseaudio
081 libnotify
082 xdg-utils
083 gtk3
084 jq
085 st
086 spotdl
087 discord
088 firefox
089 unzip
090 imgclr
091 grim
092 eww-wayland
093 wayland
094 swaylock-effects
095 swaybg
096 git
097 pstree
098 mpv
099 xdotool
100 spotify
101 brightnessctl
102 pamixer
103 nix-prefetch-git
104 python3
105 brillo
106 slop
107 ripgrep
108 maim
109 wirelesstools
110 xorg.xf86inputevdev
111 xorg.xf86inputsynaptics
112 xorg.xf86inputlibinput
113 xorg.xorgserver
114 xorg.xf86videoati
115 ];
116 # SETTING THE DEFAULT SHELL
117 environment.shells = with pkgs; [ zsh ];
118
119 programs.dconf.enable = true;
120 qt = {
121 enable = true;
122 platformTheme = "gtk2";
123 style = "gtk2";
124 };
125
126 # PRINTING // BLUETOOTH
127 services.printing.enable = true;
128 hardware.bluetooth = {
129 enable = true;
130 powerOnBoot = false;
131 };
132 services.xserver = {
133 layout = "us";
134 xkbVariant = "us,";
135 };
136 security.polkit.enable = true;
137 nix = {
138 settings = {
139 experimental-features = [ "nix-command" "flakes" ];
140 trusted-users = [ "root" "@wheel" ];
141 auto-optimise-store = true;
142 warn-dirty = false;
143 };
144 gc = { ## AUTOMATICALLY DELETEING OLD BUILDS AFTER 5 DAYS
145 automatic = true;
146 options = "--delete-older-than 5d";
147 };
148 optimise.automatic = true;
149 };
150 system = {
151 copySystemConfiguration = false;
152 stateVersion = "22.11";
153 };
154}
System Specific configurations
Now this is used for:
- Overlays
- Networking
- Services
BONUS -- also learn how to install awesomewm
01{ inputs, outputs, config, pkgs, lib, self, ... }:
02{
03
04 imports = [
05 ./hardware-configuration.nix
06 ../shared
07 ];
08
09 nixpkgs = {
10 overlays = [
11 outputs.overlays.modifications
12 outputs.overlays.additions
13 inputs.nixpkgs-f2k.overlays.stdenvs
14 inputs.nixpkgs-f2k.overlays.compositors
15 (final: prev:
16 {
17 awesome = inputs.nixpkgs-f2k.packages.${pkgs.system}.awesome-git;
18 })
19 ];
20 config = {
21 # Disable if you don't want unfree packages
22 allowUnfreePredicate = _: true;
23 allowUnfree = true;
24 };
25 };
26
27 networking.hostName = "frostbyte";
28 networking.useDHCP = false;
29 networking.interfaces.wlo1.useDHCP = true;
30 boot.kernelPackages = pkgs.linuxPackages_5_15;
31 environment.systemPackages = lib.attrValues {
32 inherit (pkgs)
33 brightnessctl
34 wayland
35 android-tools;
36 };
37
38 services = {
39 gvfs.enable = true;
40 power-profiles-daemon.enable = false;
41 tlp.enable = true;
42 upower.enable = true;
43 xserver = {
44 enable = true;
45 videoDrivers = [ "amdgpu" ];
46 libinput = {
47 enable = true;
48 touchpad = {
49 tapping = true;
50 middleEmulation = true;
51 naturalScrolling = true;
52 };
53 };
54 displayManager = {
55 defaultSession = "none+awesome";
56 startx.enable = true;
57 };
58 windowManager.awesome = {
59 enable = true;
60
61 };
62 desktopManager.gnome.enable = false;
63 };
64 };
65}
If you are wondering, we will be installing hyprland
via home-manager
Home Manager
Home Manager gives you control over the user's home environment. Home-Manager fosters user-specific profiles, accommodating distinct configurations for different users on the same system. Each user can have their own tailored environment, making it versatile and adaptable for both personal and multi-user systems
For this too, we will make two directories ./home/USER
(replace USER with your username) and ./home/shared
. The first one would be for user itself and shared would be for setttings that would be common for each user
Handling Colors
01{}:
02rec {
03 wallpaper = "birdseye.jpg";
04 foreground = "d7e0e0";
05 cursorColor = "d7e0e0";
06 background = "0a1011";
07 darker = "080c0d";
08
09 color0 = "0d1617";
10 color8 = "253336";
11
12 color1 = "df5b61";
13 color9 = "f16269";
14
15 color2 = "6ec587";
16 color10 = "8dd5a0";
17
18 color3 = "de8c6a";
19 color11 = "e59575";
20
21 color4 = "659bdb";
22 color12 = "739bdf";
23
24 color5 = "c167d9";
25 color13 = "d16ee0";
26
27 color6 = "6fd1d5";
28 color14 = "7bd3e0";
29
30 color7 = "c5d7d7";
31 color15 = "cedcd9";
32
33 bg2 = "101a1b";
34 mbg = "0e1718";
35
36 contrast = "111a1b";
37 cursorline = "111a1b";
38
39 comment = "505758";
40 name = "wave";
41 neofetchpic = "verycool.png";
42}

This is how the theme looks on awesome
rec
is the programming equivalent of return
. Now we can use this file to get the colors, whereever we want
01{ inputs, config, pkgs, lib, ... }:
02let
03 spicetify-nix = inputs.spicetify-nix;
04 colors = import ../shared/cols/wave.nix { };
05 hyprland = inputs.hyprland;
06 hyprland-plugins = inputs.hyprland-plugins;
07 unstable = import
08 (builtins.fetchTarball "https://github.com/nixos/nixpkgs/archive/master.tar.gz")
09 {
10 config = config.nixpkgs.config;
11 };
12 nixpkgs-f2k = inputs.nixpkgs-f2k;
13in
14{
15 # some general info
16 home.username = "namish";
17 home.homeDirectory = "/home/namish";
18 home.stateVersion = "22.11";
19 programs.home-manager.enable = true;
20 home.file.".icons/default".source =
21 "${pkgs.phinger-cursors}/share/icons/phinger-cursors";
22
23
24 nixpkgs.overlays = [
25 ];
26 imports = [
27 ];
28 ## THIS CODE IS RUN WHENEVER HOME MANAGER REBUILDS THE HOME DIRECTORY
29 home = {
30 activation = {
31 installConfig = ''
32 if [ ! -d "${config.home.homeDirectory}/.config/nvim" ]; then
33 ${pkgs.git}/bin/git clone --depth 1 https://github.com/chadcat7/kodo ${config.home.homeDirectory}/.config/nvim
34 fi
35 ''; ## if there is no ~/.config/nvim, git clone my nvim config
36 };
37 packages = with pkgs; [
38 bc
39 chromium
40 dunst
41 wl-clipboard
42 sway-contrib.grimshot
43 xss-lock
44 htop
45 recode
46 gcc
47 go
48 gopls
49 playerctl
50 scc
51 cinnamon.nemo
52 neofetch
53 rust-analyzer
54 hsetroot
55 notion-app-enhanced
56 mpc-cli
57 pfetch
58 ffmpeg_5-full
59 neovim
60 xdg-desktop-portal
61 imagemagick
62 procps
63 killall
64 moreutils
65 cava
66 mpdris2
67 socat
68 pavucontrol
69 fzf
70 feh
71 exa
72 ];
73 };
74
75 ## IMPORTANT
76 nixpkgs.config = {
77 allowUnfree = true;
78 allowBroken = true;
79 allowUnfreePredicate = _: true;
80 };
81}
Xresources
01{ colors }:
02
03with colors; {
04 xresources = {
05 path = ".Xresources";
06 extraConfig = ''
07 '';
08 properties = {
09 "*.background" = "#${background}";
10 "*.darker" = "#${darker}";
11 "*.color0" = "#${color0}";
12 "*.color8" = "#${color8}";
13 "*.color7" = "#${color7}";
14 "*.color15" = "#${color15}";
15 "*.foreground" = "#${foreground}";
16 "*.color1" = "#${color1}";
17 "*.color9" = "#${color9}";
18 "*.color2" = "#${color2}";
19 "*.color10" = "#${color10}";
20 "*.color3" = "#${color3}";
21 "*.color11" = "#${color11}";
22 "*.color4" = "#${color4}";
23 "*.color12" = "#${color12}";
24 "*.color5" = "#${color5}";
25 "*.color13" = "#${color13}";
26 "*.color6" = "#${color6}";
27 "*.color14" = "#${color14}";
28 "*.contrast" = "#${contrast}";
29 "*.cursorline" = "#${cursorline}";
30 "*.comment" = "#${comment}";
31 "st.borderpx" = 32;
32 };
33 };
34}
I think this piece of code pretty self explanantory
1imports = [
2 (import ../shared/xresources.nix { inherit colors; })
3];
And then also import it
Hyprland
The only thing we have to do for installing hyprland is enable it. (now that i read this sentence again, it feels really dumb). Anyways create file ./home/USER/conf/ui/hyprland/default.nix
01{ config, lib, pkgs, hyprland, colors, ... }:
02
03{
04 systemd.user.targets.hyprland-session.Unit.Wants = [ "xdg-desktop-autostart.target" ];
05 wayland.windowManager.hyprland = with colors; {
06 enable = true;
07 package = hyprland.packages.${pkgs.system}.hyprland;
08 systemdIntegration = true;
09 extraConfig = ''
10 .....
11 exec = swaybg -i ~/.wallpapers/${name}/${wallpaper} &
12 .....
13 '';
14 };
15}
This was done considering you have wallpapers in .wallpapers/wave/wallpaper.png
or something like that. And also do not forget to add in your extra config duh. 😑
And then import this file in your home.nix
1imports = [
2 ...
3 (import ./conf/ui/hyprland/default.nix { inherit config pkgs lib hyprland colors; })
4];
Waybar
Instead of using the waybar in official nix packages repositories, we will use the one available from hyprland
flake input we used.
01{ config, lib, pkgs, hyprland, colors, ... }:
02
03{
04 programs.waybar =
05 with colors; {
06 enable = true;
07 package = hyprland.packages.${pkgs.system}.waybar-hyprland;
08 systemd = {
09 enable = false;
10 target = "graphical-session.target";
11 };
12 style = ''
13 window#waybar {
14 background-color: #${background};
15 color: #${foreground};
16 border-bottom: none;
17 }
18 * {
19 font-size: 16px;
20 min-height: 0;
21 font-family: "Iosevka Nerd Font", "Material Design Icons Desktop";
22 }
23 ....
24 '';
25 settings = [{
26 height = 35;
27 layer = "top";
28 position = "top";
29 tray = { spacing = 10; };
30 modules-center = [ "clock" ];
31 modules-left = [ "hyprland/workspaces" ];
32 modules-right = [
33 "network"
34 "tray"
35 ];
36 "hyprland/workspaces" = {
37 on-click = "activate";
38 all-outputs = true;
39 format = "{icon}";
40 disable-scroll = true;
41 active-only = false;
42 format-icons = {
43 default = " ";
44 persistent = " ";
45 focused = " ";
46 };
47 persistent_workspaces = {
48 "1" = [ ];
49 "2" = [ ];
50 "3" = [ ];
51 "4" = [ ];
52 "5" = [ ];
53 };
54 };
55 clock = {
56 format = "{:%d %A %H:%M}";
57 tooltip-format = "{:%Y-%m-%d | %H:%M}";
58 };
59 network = {
60 interval = 1;
61 on-click = "eww open --toggle control";
62 format-disconnected = " ";
63 format-wifi = " ";
64 };
65 "custom/power" = {
66 on-click = "powermenu &";
67 format = " ";
68 };
69 }];
70 };
71}
and ofc import this too
1imports = [
2 ...
3 (import ./conf/utils/dunst/default.nix { inherit colors pkgs; })
4];
Wezterm
Wezterm may not be the most minimal terminal, but is still better than that bloated piece of shit. Yes I have changed my terminal yet again. (future blog probably soon). Wezterms font rendering is the most alike to ST and it can also change colorschemes instantly, also has ligature support, and much more. (and i am not even using the git version). Create a directory ./home/USER/conf/term/wezterm
and create two files default.nix
and colors.nix
01{ colors, ... }:
02with colors; {
03 followSystem = {
04 # basic colors
05 background = "#${background}";
06 cursor_bg = "#${foreground}";
07 cursor_border = "#${foreground}";
08 cursor_fg = "#${color8}";
09 foreground = "#${foreground}";
10 selection_bg = "#${color15}";
11 selection_fg = "#${background}";
12 split = "#${mbg}";
13
14 # base16
15 ansi = [
16 "#${color0}"
17 "#${color1}"
18 "#${color2}"
19 "#${color3}"
20 "#${color4}"
21 "#${color5}"
22 "#${color6}"
23 "#${color7}"
24 ];
25 brights = [
26 "#${color8}"
27 "#${color9}"
28 "#${color10}"
29 "#${color11}"
30 "#${color12}"
31 "#${color13}"
32 "#${color14}"
33 "#${color15}"
34 ];
35
36 # tabbar
37 tab_bar = {
38 background = "#${color8}";
39 active_tab = {
40 bg_color = "#${background}";
41 fg_color = "#${foreground}";
42 };
43 inactive_tab = {
44 bg_color = "#${color8}";
45 fg_color = "#${foreground}";
46 };
47 inactive_tab_hover = {
48 bg_color = "#${color0}";
49 fg_color = "#${foreground}";
50 };
51 inactive_tab_edge = "#${color0}";
52 new_tab = {
53 bg_color = "#${color8}";
54 fg_color = "#${color7}";
55 };
56 new_tab_hover = {
57 bg_color = "#${color0}";
58 fg_color = "#${foreground}";
59 };
60 };
61 };
62}
01{ pkgs, colors, ... }:
02
03with colors; {
04 programs.wezterm = {
05 enable = true;
06 colorSchemes = import ./colors.nix {
07 inherit colors;
08 };
09 extraConfig = ''
10 local wez = require('wezterm')
11 return {
12 default_prog = { 'zsh' },
13 cell_width = 0.85,
14 front_end = "OpenGL",
15 enable_wayland = true,
16 scrollback_lines = 1024,
17 font = wez.font_with_fallback({
18 "Iosevka Nerd Font",
19 "Material Design Icons",
20 }),
21 dpi = 96.0,
22 bold_brightens_ansi_colors = true,
23 font_rules = {
24 {
25 italic = true,
26 font = wez.font("Iosevka Nerd Font", { italic = true })
27 }
28 },
29 font_size = 14.0,
30 line_height = 1.15,
31 harfbuzz_features = { 'calt=1', 'clig=1', 'liga=1' },
32 color_scheme = "followSystem",
33 window_padding = {
34 left = "24pt", right = "24pt",
35 bottom = "24pt", top = "24pt"
36 },
37 default_cursor_style = "SteadyUnderline",
38 enable_scroll_bar = false,
39 warn_about_missing_glyphs = false,
40 enable_tab_bar = true,
41 use_fancy_tab_bar = false,
42 hide_tab_bar_if_only_one_tab = true,
43 show_tab_index_in_tab_bar = false,
44 window_close_confirmation = "NeverPrompt",
45 inactive_pane_hsb = {
46 saturation = 1.0, brightness = 0.8
47 },
48 check_for_updates = false,
49 }
50 '';
51 };
52}
1imports = [
2 ...
3 (import ./conf/term/wezterm/default.nix { inherit pkgs colors; })
4];
Dunst
For notifications, there are now many options for wayland but I am still going to be using dunst because I had the least trouble configuring it. Nix considers dunst
to be service instead of program, therefore, programs.dunst
becomes services.dunst
. The configuration file for dunst will be at ./home/USER/conf/utils/dunst/default.nix
01{ colors, pkgs }: with colors;{
02 services.dunst = {
03 enable = true;
04 settings = {
05 global = {
06 follow = "mouse";
07 width = 500;
08 origin = "top-center";
09 alignment = "left";
10 vertical_alignment = "center";
11 ellipsize = "middle";
12 offset = "15x15";
13 padding = 15;
14 horizontal_padding = 15;
15 text_icon_padding = 15;
16 icon_position = "left";
17 min_icon_size = 48;
18 max_icon_size = 64;
19 progress_bar = true;
20 progress_bar_height = 8;
21 progress_bar_frame_width = 1;
22 progress_bar_min_width = 150;
23 progress_bar_max_width = 300;
24 separator_height = 2;
25 frame_width = 2;
26 frame_color = "#${mbg}";
27 separator_color = "frame";
28 corner_radius = 8;
29 transparency = 0;
30 gap_size = 8;
31 line_height = 0;
32 notification_limit = 0;
33 idle_threshold = 120;
34 history_length = 20;
35 show_age_threshold = 60;
36 markup = "full";
37 font = "Iosevka Nerd Font 12";
38 word_wrap = "yes";
39 sort = "yes";
40 shrink = "no";
41 indicate_hidden = "yes";
42 sticky_history = "yes";
43 ignore_newline = "no";
44 show_indicators = "no";
45 stack_duplicates = true;
46 always_run_script = true;
47 hide_duplicate_count = false;
48 ignore_dbusclose = false;
49 force_xwayland = false;
50 force_xinerama = false;
51 mouse_left_click = "do_action";
52 mouse_middle_click = "close_all";
53 mouse_right_click = "close_current";
54 };
55
56 fullscreen_delay_everything = { fullscreen = "delay"; };
57 urgency_low = {
58 timeout = 3;
59 background = "#${background}";
60 foreground = "#${foreground}";
61 highlight = "#${color4}";
62 };
63 urgency_normal = {
64 timeout = 6;
65 background = "#${background}";
66 foreground = "#${foreground}";
67 highlight = "#${color4}";
68 };
69 urgency_critical = {
70 timeout = 0;
71 background = "#${background}";
72 foreground = "#${foreground}";
73 highlight = "#${color9}";
74 };
75 };
76 };
77
78}
and the tradition continues
1 imports = [
2 ...
3 (import ./conf/ui/waybar/default.nix { inherit config pkgs lib hyprland colors; })
4 ];
5
ZSH
zsh is my preferred shell (sorry fish noobs) so i will cover how to configure use zsh, create a file ./home/USER/conf/shell/zsh/default.nix
01
02{ config, colors, pkgs, lib, ... }:
03
04{
05 programs.zsh = {
06 enable = true;
07 enableAutosuggestions = true;
08 syntaxHighlighting.enable = true;
09 enableCompletion = true;
10 history = {
11 expireDuplicatesFirst = true;
12 save = 512;
13 };
14 initExtra = ''
15 bindkey "^[[H" beginning-of-line
16 bindkey "^[[4\~" end-of-line
17 bindkey "^[[3\~" delete-char
18 export PATH=${config.home.homeDirectory}/.local/bin:${config.home.homeDirectory}/.local/share/nvim/mason/bin:$PATH
19 '';
20 };
21
22}
** ADDING PLUGINS- **
Instead of using something like zplug, zgen, zpm, we will just install them, through, you guessed it, nix. We will use this to install powerlevel10k
01programs.zsh = {
02 plugins = [
03 {
04 name = "powerlevel10k";
05 src = pkgs.zsh-powerlevel10k;
06 file = "share/zsh-powerlevel10k/powerlevel10k.zsh-theme";
07 }
08 {
09 name = "powerlevel10k-config";
10 src = lib.cleanSource ./conf;
11 file = "powerlevel.zsh";
12 }
13 ];
14};
You will also need ./conf/shell/zsh/conf/powerlevel.zsh
which tou can get from here
SHELL ALIASES-
Instead of adding aliases in initExtra
we will do this
01programs.zsh = {
02 shellAliases = {
03 la = "exa -l";
04 ls = "ls --color=auto";
05 v = "nvim";
06 nf = "neofetch";
07 suda = "sudo -E -s";
08 nix-pkgs = "nix --extra-experimental-features 'nix-command flakes' search nixpkgs";
09 };
10
11}
And in the end:
1 imports = [
2 ...
3 (import ./conf/shell/zsh/default.nix { inherit config colors pkgs lib; })
4 ];

Music
This section will teach you how to set up mpd, ncmpcpp and playerctl on your system. It plays audio files, organizes playlists and maintains a music database, all while using very few resources. In order to interface with it, a separate client is needed. The client here is ncmpcpp
Here is the mpd configuration in nix
01{ config, pkgs }:
02
03{
04 services.mpd = {
05 enable = true;
06 musicDirectory = "${config.home.homeDirectory}/Music";
07 dataDir = "${config.home.homeDirectory}/.config/mpd";
08 extraConfig = ''
09 auto_update "yes"
10 restore_paused "yes"
11 audio_output {
12 type "pulse"
13 name "Pulseaudio"
14 server "127.0.0.1" # add this line - MPD must connect to the local sound server
15 }
16
17 audio_output {
18 type "fifo"
19 name "Visualizer"
20 format "44100:16:2"
21 path "/tmp/mpd.fifo"
22 }
23 audio_output {
24 type "httpd"
25 name "lossless"
26 encoder "flac"
27 port "8000"
28 max_client "8"
29 mixer_type "software"
30 format "44100:16:2"
31 }
32 '';
33 network.startWhenNeeded = true;
34
35 # Allows mpd to work with playerctl.
36 home.packages = [ pkgs.playerctl ];
37 services.mpdris2.enable = true;
38 services.playerctld.enable = true;
39 };
40}
According to the arch wiki: Ncmpcpp is an mpd client (compatible with mopidy) with a UI very similar to ncmpc, but it provides new useful features such as support for regular expressions for library searches, extended song format, items filtering, the ability to sort playlists, and a local filesystem browser.
For ncmpcpp
01{config, pkgs }:
02{
03 programs.ncmpcpp = {
04 enable = true;
05 package = pkgs.ncmpcpp.override {
06 visualizerSupport = true;
07 clockSupport = true;
08 taglibSupport = true;
09 };
10 mpdMusicDir = "${config.home.homeDirectory}/Music";
11 settings = {
12 # Miscelaneous
13 ncmpcpp_directory = "${config.home.homeDirectory}/.config/ncmpcpp";
14 ignore_leading_the = true;
15 external_editor = "nvim";
16 message_delay_time = 1;
17 playlist_disable_highlight_delay = 2;
18 autocenter_mode = "yes";
19 centered_cursor = "yes";
20 allow_for_physical_item_deletion = "no";
21 lines_scrolled = "0";
22 follow_now_playing_lyrics = "yes";
23 lyrics_fetchers = "musixmatch";
24
25 # visualizer
26 visualizer_data_source = "/tmp/mpd.fifo";
27 visualizer_output_name = "mpd_visualizer";
28 visualizer_type = "ellipse";
29 visualizer_look = "●●";
30 visualizer_color = "blue, green";
31
32 # appearance
33 colors_enabled = "yes";
34 playlist_display_mode = "classic";
35 user_interface = "classic";
36 volume_color = "white";
37
38 # window
39 song_window_title_format = "Music";
40 statusbar_visibility = "no";
41 header_visibility = "no";
42 titles_visibility = "no";
43 # progress bar
44 progressbar_look = "━━━";
45 progressbar_color = "black";
46 progressbar_elapsed_color = "blue";
47
48 # song list
49 song_status_format = "$7%t";
50 song_list_format = "$(008)%t$R $(247)%a$R$5 %l$8";
51 song_columns_list_format = "(53)[blue]{tr} (45)[blue]{a}";
52
53 current_item_prefix = "$b$2| ";
54 current_item_suffix = "$/b$5";
55
56 now_playing_prefix = "$b$5| ";
57 now_playing_suffix = "$/b$5";
58
59 # colors
60 main_window_color = "blue";
61
62 current_item_inactive_column_prefix = "$b$5";
63 current_item_inactive_column_suffix = "$/b$5";
64
65 color1 = "white";
66 color2 = "blue";
67 };
68 };
69}
Bonus - Creating Files
to write on a file on rebuilding home manager you can use home.file
for eg writing the .xinitrc
file
1{}:
2{
3 home.file.".xinitrc".text = ''
4 #!/usr/bin/env bash
5 exec dbus-run-session awesome
6 '';
7}
you can also make bin files with this, just set executable
to true
01{ colors }:
02{
03 home.file.".local/bin/lock" = {
04 executable = true;
05 text = ''
06 #!/bin/sh
07 playerctl pause
08 sleep 0.2
09 swaylock -i ~/.config/awesome/theme/wallpapers/${colors.name}/${colors.wallpaper} --effect-blur 10x10
10 '';
11 };
12}
Dynamic GTK Theming
For dynamic themeing, we will just use phocus and then just subsititute the colors with patches. You are recommended to get your patches from here. So this is the derivation we need for it -
01{ stdenvNoCC
02, fetchFromGitHub
03, nodePackages
04, colors
05,
06}:
07stdenvNoCC.mkDerivation rec {
08 pname = "phocus";
09 version = "0cf0eb35a927bffcb797db8a074ce240823d92de";
10
11 src = fetchFromGitHub {
12 owner = "phocus";
13 repo = "gtk";
14 rev = version;
15 sha256 = "sha256-URuoDJVRQ05S+u7mkz1EN5HWquhTC4OqY8MqAbl0crk=";
16 };
17
18 patches = [
19 ../patches/npm.diff
20 ../patches/gradients.diff
21 ../patches/substitute.diff
22 ];
23
24 postPatch = ''
25 substituteInPlace scss/gtk-3.0/_colors.scss \
26 --replace "@bg0@" "#${colors.background}" \
27 --replace "@bg1@" "#${colors.contrast}" \
28 --replace "@bg2@" "#${colors.color8}"\
29 --replace "@bg3@" "#${colors.color0}" \
30 --replace "@bg4@" "#${colors.comment}" \
31 --replace "@red@" "#${colors.color1}" \
32 --replace "@lred@" "#${colors.color9}" \
33 --replace "@orange@" "#${colors.color3}" \
34 --replace "@lorange@" "#${colors.color11}" \
35 --replace "@yellow@" "#${colors.color3}" \
36 --replace "@lyellow@" "#${colors.color11}" \
37 --replace "@green@" "#${colors.color2}" \
38 --replace "@lgreen@" "#${colors.color10}" \
39 --replace "@cyan@" "#${colors.color6}" \
40 --replace "@lcyan@" "#${colors.color15}" \
41 --replace "@blue@" "#${colors.color4}" \
42 --replace "@lblue@" "#${colors.color12}" \
43 --replace "@purple@" "#${colors.color5}" \
44 --replace "@lpurple@" "#${colors.color14}" \
45 --replace "@pink@" "#${colors.color5}" \
46 --replace "@lpink@" "#${colors.color14}" \
47 --replace "@primary@" "#${colors.foreground}" \
48 --replace "@secondary@" "#${colors.color15}"
49 '';
50
51 nativeBuildInputs = [ nodePackages.sass ];
52 installFlags = [ "DESTDIR=$(out)" "PREFIX=" ];
53}
And then we can call it in the home.nix file
1 gtk = {
2 enable = true;
3 gtk3.extraConfig.gtk-decoration-layout = "menu:";
4 theme.name = "phocus";
5 };
Nix Shell
Nix-shell is a command-line tool and concept within the Nix package manager that enables the creation of isolated development environments for software projects. It allows developers to specify the exact dependencies and environment required for a project, ensuring consistency and reproducibility across different systems and projects.
Here is an example shell.nix
1{ pkgs ? import <nixpkgs> {} }:
2 pkgs.mkShell {
3 # nativeBuildInputs is usually what you want -- tools you need to run
4 nativeBuildInputs = with pkgs.buildPackages; [ lua52Packages.lua cmake gcc pam gnumake ];
5}
To enter the shell we will use
1$ nix-shell shell.nix
Conclusion
whew, if you made it there, i hope you learned something from this. if there is an error you can contact me at discord @ chadcat7
. For a reference you can check out my dots