bedHedd's NixOS Adventure

background

I recently built a computer for my dad who wants to get into local llms.

I wanted to write this post so that if I have to fix his computer, I have a reference of how I configured it. Also this was a great excuse opportunity to learn about nix. If the experience is good, I might migrate from Fedora.

Stick around to see my updates

why nix?

My initial plan was to use Nobara, as I use it on my HTPC and has a pretty painless installation and if my dad wanted to play games it would be relatively straightforward for him.

I was thinking of using nix as the package manager for ollama, vscodium and ROCm, so that way if he needs to reset the computer, it should be relatively easy to get back to work. However, I couldn’t find anyone online who did this kind of setup.

My main hesitation with NixOS was that the OS and packages wouldn’t get as many updates as bleeding edge distros and it would lead to potential issues with hardware updates. As I did more research this was not the case. Specifically at 0:52 in No Boilerplate’s video where he talks about how Nix has the most number of new packages

Also his story at 2:00 is the same experience I had with arch and fedora, where a update borked my desktop manager

https://youtu.be/CwfKlX3rA6E?si=SkteVHSzmzE_syOI&t=120

Also in the event that I need to do remote debugging, it should be easier for me to replicate his environment.

I also remembered that Nix has been used for gaming

4 Likes

TODOs

  • install git
  • setup nix config repo

Tweaks

rename the hostname

I followed the guide linked by the nix forums

here

which suggested looking for the term networking.hostName within configuration.nix

linking a custom configuration with git for version control

One of the benefits mentioned by the nix videos is the ability to use version control to manage packages
This was a good guide

modifications to these instructions

  • I structured my directory to follow one similar to this example
  • I made the git repo within my nix-config in my Documents folder. I plan to expand by making sub folders configurations for their own machines.
  • I moved the hardware-configuration.nix to the folder as well
  • I ran the ls -la to get my account name for the chown command for configuration.nix and hardware-configuration.nix

homemanager

I wanted to change the default text editor from nano to neovim. The wiki recommends using home manager
https://nixos.wiki/wiki/Home_Manager
Looking online I found this guide.
https://nix-community.github.io/home-manager/index.xhtml#sec-install-nixos-module
I wanted to make sure my configuration.nix would have this included so I followed the following instructions

I edited my configuration.nix to include the following

let
  home-manager = builtins.fetchTarball https://github.com/nix-community/home-manager/archive/release-24.11.tar.gz;
in
{
  imports =
    [
      ./hardware-configuration.nix
      (import "${home-manager}/nixos")
    ];

  users.users.eve.isNormalUser = true;
  home-manager.users.eve = { pkgs, ... }: {
    home.packages = [ pkgs.atool pkgs.httpie ];
    programs.bash.enable = true;
  
    # The state version is required and should stay at the version you
    # originally installed.
    home.stateVersion = "24.11";
  };

neovim

I wanted to set the default text editor to neovim

copying text from neovim to the rest of the system

while writing this guide I wanted to copy the text from neovim to the system keyboard

I added the following entries to my configuration.nix following the OP’s post

# /etc/nixos/configuration.nix
environment.systemPackages = with pkgs; [
  # ...
  
  wl-clipboard
  xclip
];

Then I ran :checkhealth in neovim to confirm that the modules got installed. For whatever reason it used xclip which was the same output as the op

provider.clipboard: require("provider.clipboard.health").check()

Clipboard (optional) ~
- OK Clipboard tool found: xclip

This reply suggested nvim --clean, which opened a new neovim window. I then ran :checkhealth to see if xclip went away

provider.clipboard: require("provider.clipboard.health").check()

Clipboard (optional) ~
- OK Clipboard tool found: wl-copy

I highlighted some text copied it and checked if it would paste


This is great, but there are too many configurations + repo structures.
I’m going to follow this guide because they have a video of getting a repo setup

following the video guide

changes from flakes guide

  • add nix.settings.experimental-features = [ "nix-command" "flakes"]; to configuration.nix
  • create a flake.nix
  • edit flake.nix
    • rename the hostname to my machine name
    • add the configuration.nix path as a path
    • structure flake to be similar to michaelpj’s config
      • copied their modules folder and home.nix, home-manager.nix, and entertainment.nix

Hey there,

I have been using nixos for about 6 months now and I think it is awesome. I have found that my favorite flake thing is Snowfall lib. I am happy to help if you have any specific questions.

The way I went about organizing stuff is to have a set of modules for NixOS and Home Manager that I keep in a public repo, but have all my host configs in a private repo (so as to hopefully not leak stuff like domains and IP address layouts lol). Also I have another separate repo for secrets using sops-nix.

Anyway happy to see more people get into NixOS, as I think it’s pretty great.

1 Like

interesting. I took a look at snowflake. Can you explain why you use snowfall flake over others.

Does it automatically create the folders within the modules?

I am most familiar with python environments, so if there’s something that can declaratively add packages using the cli (ie if I do uv add pandas my pyproject.toml file gets pandas appended to the dependency) similar to uv or poetry. I would use that.

I want a package where if I run a command
package-manager add package, package gets added to my nix environment or the flake file

So, there are a lot of things that do similar stuff for flakes - flake-utils, flakelight, haumea…I just found snowflake first and continue to think that it removes enough boilerplate to be worth using. It does want a specific filesystem layout, but that actually works for me. You’ll find that there are a ton of different ways to do things in NixOS and as a result there’s a lot of personality in every config.

Nope, but it does import everything for you automagically which tends to clean up imports a good amount.

I don’t think I have seen anything specifically which does this. I think generally you want to have that stuff be different enough for hosts/users that it’s not worth it to have a global add like that. Plus a lot of times there’s not a single place you would put that kinda stuff - for example my config has each host in its own directory, and sometimes even in different files in that directory which are imported into default.nix.

As an example, my main workstation config is in nixos-snowzen/systems/x86-64-linux/titan/ which has the following config files in it: default.nix, hardware-configuration.nix, networking.nix, stylix.nix, and users.nix. These could in theory all just be in default.nix as that is the only required file, but I like splitting it up. The system itself really only has a few packages that are installed globally - things I want if somehow my user gets messed up: vim, git, wget, bash. It also defines a bunch of stuff at the system level - what services I want enabled at the system level like AMD GPU stuff, lm-sensors, bluetooth, zfs, podman, xwindows config (though my actual GUI config files live with my user) including display resolution, VRR & DPI settings. This is also where I configure rocm, ollama, etc.

Most of that stuff is actually in my zen config modules in my zenix-modules repo which I linked in my last post. The config for each thing is defined there, and I just enable/disable/customize in the system config with something like:

# since zenix is in a different flake from my system config, zenix modules do need to be imported:
imports = [
  ...
  inputs.zenix.nixosModules.zenix
  ...
];

zen = {
  system = {
    zfs.enable = true;
    podman.enable = true;
  };
  ...
  ai = {
    rocm.enable = true;
    ollama.enable = true;
    ollama.host = "0.0.0.0";
  };
  ...
};

To make this a bit more concrete as to what this actually does, you can see how each of these options is defined and what they actually configure here (zfs), here (podman), here (rocm), and here (ollama).

Obviously it has taken me quite a while to get to this point. My config did not come about over night, it has taken a lot of work. Even though it’s nowhere near perfect, I am pretty happy with it.

My users are configured pretty similarly, and they tend to just use a bunch of stuff from my zenix-modules for configuration, though there are a few tweaks and system/user-specific stuff configured outside of zenix.

Another tip is to check out awesome-nix which has a pretty good collection of tools you might find useful. Once you start using flakes, I have found that nh or nix helper is pretty rad and I use it instead of nixos-rebuild all the time now. The output is much nicer.

I am getting on a plane later today so I may or may not be able to reply until tomorrow, but I am looking forward to seeing your progress! NixOS is fun. I hope you enjoy your journey.

1 Like

took a look at snowfall lib. Based on your config, it looks like the main advantage is if I want to break my repo into folders and subfolder.

For my case, I want to keep it simple for now with all the files accessible. If I need more organization, I’ll come back to it

Yep! That’s how I started too. Once you decide if you like it and want to use NixOS on multiple computers, that’s when frameworks like this really start to be useful. Especially when you start to want to break up configs and use chunks of them here and there.

I guess one other handy thing is being able to very easily use overlays when you want to use packages from a different channel - for example when most of your config is using a release (say 25.05 soon!) but you want some packages from unstable, Snowfall lib makes that very easy. But that’s definitely a bit more advanced use-case - I only really use that for getting newer kernels and ollama-webui (the 24.11 version of that package doesn’t support the “thinking…” stuff from models like deepseek-r1 but the unstable version does).

1 Like

continuing with the playlist

the video goes over the standalone installer from the manual
https://nix-community.github.io/home-manager/

changes from the home manager guide

I was going to follow the video, but after watching it, I realized that Michael’s config had already covered most of the content.

initial changes

standalone vs nix os module

Initially I was thinking of using the NixOS module as the video mentioned it would be easier to manage users at a system level, but some folks on the internet brought up 2 benefits that made me reconsider.

  1. Standalone doesn’t write a entry to the boot manager, so you frequently change the home configuration, your boot will get spammed
  2. You can separate user space from system

Also when learning, it is much easier to follow someone else’s guide and modify the instructions

https://old.reddit.com/r/NixOS/comments/mygjc1/homemanager_as_nixos_module_or_as_standalone/

benefit #1 no spam to boot entries

benefit #2 separation of system and userspace

explaining Michael’s config with chatgpt

I realized that my customizations had gone off both tutorial paths. Fortunately I had chatgpt to help explain how it works. I had it summarize the questions and answers using discourse

Chatgpt questions

Q1: How does Michael’s config interact with Home Manager?


Q2: Why do I get a flake error about missing homeConfigurations?


Q3: How do I manage my dotfiles using Home Manager in Michael’s setup?


Q4: How do I link my dotfiles directory in the repo with Home Manager?


Q5: Do I have to declare each dotfile in Home Manager explicitly?


Q6: What about relative paths if my home.nix is in a modules folder?


Q7: How can I add fish, fzf, and zoxide and share this configuration with a new user?

updates to neovim with home manager

I previously configured neovim this way, but now that I have michael’s config, I need to update my files.

There are 2 crucial changes

  1. Move neovim to home.nix within my modules folder
  2. Enable auto/smart indent

updating home.nix

I started by removing neovim from my configuration.nix.
then I added a new entry within the programs section of home.nix. I did the same with librewolf

  programs = {
   # ...
    neovim = {
      enable = true;
      viAlias = true;
      vimAlias = true;

      # Pass configuration options directly
      extraConfig = ''
        set autoindent
        set smartindent
        filetype plugin indent on
      '';

      # Optionally, include plugins using an overlay or package reference.
      # For example, using vim-nix if it’s available as a package:
      plugins = with pkgs.vimPlugins; [ vim-nix ];
    };

using git to track changes

since michael’s config has git setup in the home.nix.

# within programs section of home.nix
    git = {
      enable = true;
      package = pkgs.gitAndTools.gitFull;
      includes = [
        # { path = ../dotfiles/gitconfig; } # git account config for paths
        # { condition = "gitdir:iohk/"; path = ../dotfiles/gitconfig-iohk; } 
        # { condition = "gitdir:input-output-hk/"; path = ../dotfiles/gitconfig-iohk; }
        # { condition = "gitdir:IntersectMBO/"; path = ../dotfiles/gitconfig-iohk; }
        # { condition = "gitdir:cardano-foundation/"; path = ../dotfiles/gitconfig-iohk; }
        # { condition = "gitdir:circuithub/"; path = ../dotfiles/gitconfig-circuithub; }
      ];
    }; 

All I needed to do was run the following commands

  1. initialize a git repo

    • git init
  2. configure my commit username and email, replace $email and $username with your github username and email

    • git config user.email "$email"
    • `git config user.name “$username”
  3. check for any changes using git status. The command will return any files that need to be commited

    • git status
    • git status
      On branch master
      Untracked files:
      (use "git add <file>..." to include in what will be committed)
      modules/file.nix
      
      nothing added to commit but untracked files present (use "git add" to track)
      
      
  4. add the files that you want to track. Replace $filepath-name with the relative path, so if you have a file named file.nix in the modules folder make sure to replace the $filepath-name with modules/file.nix

    • git add $filepath-name
  5. write a commit message

    • `git commit -m “added file.nix to tracking”
  6. keep track of your commits using git log. You can use git revert $hash, which is the text after

    • example output
      •  git log
         commit db8a273b0f88bfb0e40291279dd887e5181aca5e   (HEAD -> master)
         Author: bedhedd <$user.email>
        Date:   Sun Apr 13 14:27:27 2025 -0500
        
        fix fish prompt to install grc, it does not exist in 22.05
        
        • the db8a273b0f88bfb0e40291279dd887e5181aca5e is the structure of the commit hash,
      • if I needed to reset to this commit db8a273b0f88bfb0e40291279dd887e5181aca5e, I would run the command git reset db8a273b0f88bfb0e40291279dd887e5181aca5e
  7. If I want to push these changes to online github, repository, I would run

    • git push origin master
      • origin refers to your local branch
      • master refers to your remote online github repository
    • when pushing to a remote online github repository, the name of the local branch must also be available on the online remote repository. You can check which branch you are on with git status

using fish as the default shell

adding fish to home manager and NixOS

michael’s home.nix config has the following line section for bash, I want to change it so that fish is the default shell for all users

  programs = {
    home-manager.enable = true;
    direnv.enable = true;
    bash = {
      enable = true;
      initExtra = builtins.readFile ../dotfiles/.bashrc;
    };
    tmux = {
      enable = true;
      keyMode = "vi";
      extraConfig = builtins.readFile ../dotfiles/.tmux.conf;
    };

I initially tried to use chatgpt, to modify michael’s config + the nix wiki documentation on fish. It worked in adding a entry to homemanager, but failed to get fish to autostart.
https://nixos.wiki/wiki/Fish#Home_Manager
The nix wiki has the following for fish and home manager

Michael’s config didn’t had home manager configure it by the system, so I couldn’t copy paste the wiki entry. Furthermore, I wanted fish at the system level. Finally I needed comment out grc from the plugins list because it didn’t not exist in my NixOS version of 22.05


  programs = {
    home-manager.enable = true;
    direnv.enable = true;
    fish = {
      enable = true;
      interactiveShellInit = import ../dotfiles/fish-config.nix {};
      plugins = [
        #{ name = "grc"; src = pkgs.fishPlugins.grc.src; }
        #{
        #  name = "z";
        #  src = pkgs.fetchFromGitHub {
        #    owner = "jethrokuan";
        #    repo = "z";
        #    rev = "e0e1b9dfdba362f8ab1ae8c1afc7ccf62b89f7eb";
        #    sha256 = "0dbnir6jbwjpjalz14snzd3cgdysgcs3raznsijd6savad3qhijc";
        #  };
        #}
      ];
    };

I also added the line

      interactiveShellInit = import ../dotfiles/fish-config.nix {};

Doing some research and looking at the fish config, I realized that nix will autogenerate a config.fish file. the interactiveShellInit command will append any additional fish commands into. I followed a similar structure to michael’s dotfiles structure, and created a fish-config.nix file in the dotfiles folder. This will be helpful later as I add zoxide.

I created a separate file because I knew that my config.fish will get long, and did not want to make my home manager too unreadable. My personal rule for moving scripts to dedicated files is if it is >5 lines and becomes harder to read, it deserves a dedicated file.

autostarting

When it came to autostarting, Chatgpt kept hallucinating, even with web search tool on the o3-mini-high and o3-mini it still failed.
https://nixos.wiki/wiki/Fish

These are good instructions, but I didn’t know how to get it working for my setup. I modified michael’s entry to work for my setup. My rebuild command sudo nixos-rebuild switch --flake . failed to build because interactiveShellInit did not exist, I replaced it with initExtra. Ultimately this is what I used to have fish autostart

    bash = {
      enable = true;
      initExtra = ''
        if [[ $(${pkgs.procps}/bin/ps --no-header --pid=$PPID --format=comm) != "fish" && -z ''${BASH_EXECUTION_STRING} ]]
        then
          shopt -q login_shell && LOGIN_OPTION='--login' || LOGIN_OPTION=""
          exec ${pkgs.fish}/bin/fish $LOGIN_OPTION
        fi
      '';
    };  

Next on the list is to add fzf and zoxide

adding fzf and zoxide

I started out by modifying the packages section of my home.nix. The structure is:

  home = { 
    packages = with pkgs; [ 
      gnupg
      zoxide
      fzf

      # dictionaries
      # aspell
      # aspellDicts.en
    ];
    stateVersion = "22.05";
  };

After adding zoxide and fzf to the packages, I added a entry to zoxide my programs section

  programs = {
    home-manager.enable = true;
    direnv.enable = true;
    # ... other program entries, zoxide below fish
    zoxide = {
      enable = true;
      enableFishIntegration = true;
      options = ["--cmd cd | source"];:
    };

To make sure that fzf works with fish, I added the following entry to my fish config (dotfiles/fish-config.nix) based on the wiki’s fzf entry
https://nixos.wiki/wiki/Fzf

function fish_user_key_bindings
  if command -s fzf-share >/dev/null
    source (fzf-share)/key-bindings.fish
  end

  fzf_key_bindings
end

if you want to keep it in interactiveShellInit as a string you can also do that as well

Hi,

just to let you know, nixos.wiki is considered abandoned and will most likely be out of date. There is an ongoing official wiki effort at wiki.nixos.org, which forked off of the old wiki.

Blog posts usually end up being a pretty good shout as well, but be wary in copying them to the T, as stuff moves pretty fast, so your best bet is usually looking directly at the options section of search.nixos.org, or for home manager, home-manager-options.extranix.com

2 Likes

Oh that makes so much sense. I eventually figured it out.
The nixos forum and and looking at github configs seems to have more up to date configs

I got this bug

cdi
DBI connect('dbname=/nix/var/nix/profiles/per-user/root/channels/nixos/programs.sqlite','',...) failed: unable to open database file at /run/current-system/sw/bin/command-not-found line 13.
cannot open database `/nix/var/nix/profiles/per-user/root/channels/nixos/programs.sqlite' at /run/current-system/sw/bin/command-not-found line 13.

turns out my config in home manager programs was misconfigured

  programs = {
    home-manager.enable = true;
    direnv.enable = true;
    # ... other program entries, zoxide below fish
    zoxide = {
      enableFishIntegration= true;
      options = ["--cmd cd fish | source"];
    };

The correct configuration should be

  programs = {
    home-manager.enable = true;
    direnv.enable = true;
    # ... other program entries, zoxide below fish
    zoxide = {
      enable = true;
      enableFishIntegration = true;
      options = ["--cmd cd | source"];:
    };

I ran a rebuild command and it fixed the issue. I have updated the op

I wanted my amd gpu to increase the refresh rate for kde and wayland

Didn't work my display is locked at 30hz

https://www.old.reddit.com/r/NixOS/comments/1e81ait/comment/le4h0ym/
I edited my configuration.nix for the machine.

{ config, pkgs, nixos-hardware, home-manager, ... }:

{
  imports =
    [
      nixos-hardware.nixosModules.common-gpu-amd
      ./hardware-configuration.nix
      home-manager.nixosModules.home-manager
      ../../modules/home-manager.nix
    ];

However I couldn’t use the <nixos-hardware/common/gpu/amd/default.nix> because I used flakes. With the help of chatgpt and websearch I was able to use the correct import of nixos-hardware.nixosModules.common-gpu-amd.

Before that, I tried nixos-hardware.nixosModules.gpu.amdgpu, but threw errors when I tried to rebuild.

sudo nixos-rebuild switch --flake .
warning: Git tree '/home/admin/Documents/nix-config' is dirty
error:
       … while calling the 'seq' builtin
         at /nix/store/zd0x43g1jcav0xy0k6q9pdhy3bvif77n-source/lib/modules.nix:358:18:
          357|         options = checked options;
          358|         config = checked (removeAttrs config [ "_module" ]);
             |                  ^
          359|         _module = checked (config._module);

       … while evaluating a branch condition
         at /nix/store/zd0x43g1jcav0xy0k6q9pdhy3bvif77n-source/lib/modules.nix:294:9:
          293|       checkUnmatched =
          294|         if config._module.check && config._module.freeformType == null && merged.unmatchedDefns != [ ] then
             |         ^
          295|           let

       (stack trace truncated; use '--show-trace' to show the full, detailed trace)

       error: attribute 'gpu' missing
       at /nix/store/5jd3hfmz4v1r23x3c5638cz156rvhh35-source/machines/jade-tiger/configuration.nix:10:7:
            9|     [
           10|       nixos-hardware.nixosModules.gpu.amdgpu
             |       ^
           11|       ./hardware-configuration.nix

Fortunately chatgpt found this post
https://old.reddit.com/r/NixOS/comments/18m67ew/too_stupid_to_figure_out_how_to_use_nixoshardware/ke282nh/

I’m stuck. Does anyone know how to fix this bug?

I’m using Wayland, I have Kernel 6.14.1. No amount of tweaking has fixed this

debug commands

uname -r
6.14.1
sudo dmesg | grep -i amdgpu
[sudo] password for admin: 
[    0.633911] stage-1-init: [Thu Apr 17 02:15:54 UTC 2025] loading module amdgpu...
[    3.590142] [drm] amdgpu kernel modesetting enabled.
[    3.599059] amdgpu: Virtual CRAT table created for CPU
[    3.599077] amdgpu: Topology: Add CPU node
[    3.604028] amdgpu 0000:08:00.0: amdgpu: detected ip block number 0 <soc21_common>
[    3.604031] amdgpu 0000:08:00.0: amdgpu: detected ip block number 1 <gmc_v11_0>
[    3.604034] amdgpu 0000:08:00.0: amdgpu: detected ip block number 2 <ih_v6_0>
[    3.604036] amdgpu 0000:08:00.0: amdgpu: detected ip block number 3 <psp>
[    3.604038] amdgpu 0000:08:00.0: amdgpu: detected ip block number 4 <smu>
[    3.604040] amdgpu 0000:08:00.0: amdgpu: detected ip block number 5 <dm>
[    3.604043] amdgpu 0000:08:00.0: amdgpu: detected ip block number 6 <gfx_v11_0>
[    3.604045] amdgpu 0000:08:00.0: amdgpu: detected ip block number 7 <sdma_v6_0>
[    3.604047] amdgpu 0000:08:00.0: amdgpu: detected ip block number 8 <vcn_v4_0>
[    3.604049] amdgpu 0000:08:00.0: amdgpu: detected ip block number 9 <jpeg_v4_0>
[    3.604051] amdgpu 0000:08:00.0: amdgpu: detected ip block number 10 <mes_v11_0>
[    3.627509] amdgpu 0000:08:00.0: No more image in the PCI ROM
[    3.627533] amdgpu 0000:08:00.0: amdgpu: Fetched VBIOS from ROM BAR
[    3.627539] amdgpu: ATOM BIOS: 113-D7040100-115
[    3.634329] amdgpu 0000:08:00.0: amdgpu: CP RS64 enable
[    3.644879] amdgpu 0000:08:00.0: vgaarb: deactivate vga console
[    3.645792] amdgpu 0000:08:00.0: amdgpu: Trusted Memory Zone (TMZ) feature not supported
[    3.645839] amdgpu 0000:08:00.0: amdgpu: MEM ECC is not presented.
[    3.645841] amdgpu 0000:08:00.0: amdgpu: SRAM ECC is not presented.
[    3.645867] amdgpu 0000:08:00.0: amdgpu: VRAM: 20464M 0x0000008000000000 - 0x00000084FEFFFFFF (20464M used)
[    3.645870] amdgpu 0000:08:00.0: amdgpu: GART: 512M 0x00007FFF00000000 - 0x00007FFF1FFFFFFF
[    3.646585] [drm] amdgpu: 20464M of VRAM memory ready
[    3.646588] [drm] amdgpu: 7955M of GTT memory ready.
[    3.718385] amdgpu 0000:08:00.0: amdgpu: reserve 0x1300000 from 0x84fc000000 for PSP TMR
[    3.865171] amdgpu 0000:08:00.0: amdgpu: RAP: optional rap ta ucode is not available
[    3.865174] amdgpu 0000:08:00.0: amdgpu: SECUREDISPLAY: securedisplay ta ucode is not available
[    3.865205] amdgpu 0000:08:00.0: amdgpu: smu driver if version = 0x0000003d, smu fw if version = 0x00000040, smu fw program = 0, smu fw version = 0x004e8000 (78.128.0)
[    3.865208] amdgpu 0000:08:00.0: amdgpu: SMU driver if version not matched
[    4.014542] amdgpu 0000:08:00.0: amdgpu: SMU is initialized successfully!
[    4.386243] amdgpu: HMM registered 20464MB device memory
[    4.388143] kfd kfd: amdgpu: Allocated 3969056 bytes on gart
[    4.388155] kfd kfd: amdgpu: Total number of KFD nodes to be created: 1
[    4.388204] amdgpu: Virtual CRAT table created for GPU
[    4.388606] amdgpu: Topology: Add dGPU node [0x744c:0x1002]
[    4.388609] kfd kfd: amdgpu: added device 1002:744c
[    4.388622] amdgpu 0000:08:00.0: amdgpu: SE 6, SH per SE 2, CU per SH 8, active_cu_number 84
[    4.388627] amdgpu 0000:08:00.0: amdgpu: ring gfx_0.0.0 uses VM inv eng 0 on hub 0
[    4.388630] amdgpu 0000:08:00.0: amdgpu: ring comp_1.0.0 uses VM inv eng 1 on hub 0
[    4.388632] amdgpu 0000:08:00.0: amdgpu: ring comp_1.1.0 uses VM inv eng 4 on hub 0
[    4.388634] amdgpu 0000:08:00.0: amdgpu: ring comp_1.2.0 uses VM inv eng 6 on hub 0
[    4.388636] amdgpu 0000:08:00.0: amdgpu: ring comp_1.3.0 uses VM inv eng 7 on hub 0
[    4.388639] amdgpu 0000:08:00.0: amdgpu: ring comp_1.0.1 uses VM inv eng 8 on hub 0
[    4.388641] amdgpu 0000:08:00.0: amdgpu: ring comp_1.1.1 uses VM inv eng 9 on hub 0
[    4.388643] amdgpu 0000:08:00.0: amdgpu: ring comp_1.2.1 uses VM inv eng 10 on hub 0
[    4.388645] amdgpu 0000:08:00.0: amdgpu: ring comp_1.3.1 uses VM inv eng 11 on hub 0
[    4.388647] amdgpu 0000:08:00.0: amdgpu: ring sdma0 uses VM inv eng 12 on hub 0
[    4.388650] amdgpu 0000:08:00.0: amdgpu: ring sdma1 uses VM inv eng 13 on hub 0
[    4.388652] amdgpu 0000:08:00.0: amdgpu: ring vcn_unified_0 uses VM inv eng 0 on hub 8
[    4.388654] amdgpu 0000:08:00.0: amdgpu: ring vcn_unified_1 uses VM inv eng 1 on hub 8
[    4.388656] amdgpu 0000:08:00.0: amdgpu: ring jpeg_dec uses VM inv eng 4 on hub 8
[    4.388659] amdgpu 0000:08:00.0: amdgpu: ring mes_kiq_3.1.0 uses VM inv eng 14 on hub 0
[    4.391958] amdgpu 0000:08:00.0: amdgpu: Using BAMACO for runtime pm
[    4.392576] amdgpu 0000:08:00.0: [drm] Registered 4 planes with drm panic
[    4.392578] [drm] Initialized amdgpu 3.61.0 for 0000:08:00.0 on minor 0
[    4.401718] fbcon: amdgpudrmfb (fb0) is primary device
[    4.583797] amdgpu 0000:08:00.0: [drm] fb0: amdgpudrmfb frame buffer device
[    9.659478] snd_hda_intel 0000:08:00.1: bound 0000:08:00.0 (ops amdgpu_dm_audio_component_bind_ops [amdgpu])
qdbus org.kde.KWin /KWin supportInformation
KWin Support Information:
The following information should be used when requesting support on e.g. https://discuss.kde.org.
It provides information about the currently running instance, which options are used,
what OpenGL driver and which effects are running.
Please post the information provided underneath this introductory text to a paste bin service
like https://paste.kde.org instead of pasting into support threads.

==========================

Version
=======
KWin version: 6.3.4
Qt Version: 6.8.2
Qt compile version: 6.8.2
XCB compile version: 1.17.0

Operation Mode: Wayland

Build Options
=============
KWIN_BUILD_DECORATIONS: yes
KWIN_BUILD_TABBOX: yes
KWIN_BUILD_ACTIVITIES: yes
HAVE_X11_XCB: yes
HAVE_GLX: yes

X11
===
Vendor: The X.Org Foundation
Vendor Release: 12401006
Protocol Version/Revision: 11/0
SHAPE: yes; Version: 0x11
RANDR: yes; Version: 0x14
DAMAGE: yes; Version: 0x11
Composite: yes; Version: 0x4
RENDER: yes; Version: 0xb
XFIXES: yes; Version: 0x50
SYNC: yes; Version: 0x31
GLX: yes; Version: 0x0

Decoration
==========
Plugin: org.kde.breeze
Theme: 
Plugin recommends border size: None
onAllDesktopsAvailable: false
alphaChannelSupported: true
closeOnDoubleClickOnMenu: false
decorationButtonsLeft: 0, 2
decorationButtonsRight: 6, 3, 4, 5
borderSize: 0
gridUnit: 10
font: Noto Sans,10,-1,0,400,0,0,0,0,0,0,0,0,0,0,1
smallSpacing: 2
largeSpacing: 10

Output backend
==============
Name: DRM
Atomic Mode Setting on GPU 0: true

Cursor
======
themeName: breeze_cursors
themeSize: 24

Options
=======
focusPolicy: ClickToFocus
xwaylandCrashPolicy: 1
xwaylandMaxCrashCount: 3
nextFocusPrefersMouse: false
clickRaise: true
autoRaise: false
autoRaiseInterval: 0
delayFocusInterval: 0
shadeHover: false
shadeHoverInterval: 250
separateScreenFocus: true
placement: 5
activationDesktopPolicy: SwitchToOtherDesktop
focusPolicyIsReasonable: true
borderSnapZone: 10
windowSnapZone: 10
centerSnapZone: 0
snapOnlyWhenOverlapping: false
edgeBarrier: 100
cornerBarrier: 1
rollOverDesktops: false
focusStealingPreventionLevel: 1
operationTitlebarDblClick: 5000
operationMaxButtonLeftClick: 5000
operationMaxButtonMiddleClick: 5015
operationMaxButtonRightClick: 5014
commandActiveTitlebar1: MouseRaise
commandActiveTitlebar2: MouseNothing
commandActiveTitlebar3: MouseOperationsMenu
commandInactiveTitlebar1: MouseActivateAndRaise
commandInactiveTitlebar2: MouseNothing
commandInactiveTitlebar3: MouseOperationsMenu
commandWindow1: MouseActivateRaiseOnReleaseAndPassClick
commandWindow2: MouseActivateAndPassClick
commandWindow3: MouseActivateAndPassClick
commandWindowWheel: MouseNothing
commandAll1: MouseUnrestrictedMove
commandAll2: MouseToggleRaiseAndLower
commandAll3: MouseUnrestrictedResize
keyCmdAllModKey: 16777250
doubleClickBorderToMaximize: true
condensedTitle: false
electricBorderMaximize: true
electricBorderTiling: true
electricBorderCornerRatio: 0.25
borderlessMaximizedWindows: false
killPingTimeout: 5000
compositingMode: 1
useCompositing: true
hiddenPreviews: 1
glSmoothScale: 2
glStrictBinding: true
glStrictBindingFollowsDriver: true
glPreferBufferSwap: AutoSwapStrategy
glPlatformInterface: 2
windowsBlockCompositing: true
allowTearing: true
interactiveWindowMoveEnabled: true

Screen Edges
============
desktopSwitching: false
desktopSwitchingMovingClients: false
cursorPushBackDistance: 1x1
actionTopLeft: 0
actionTop: 0
actionTopRight: 0
actionRight: 0
actionBottomRight: 0
actionBottom: 0
actionBottomLeft: 0
actionLeft: 0

Screens
=======
Number of Screens: 1

Screen 0:
---------
Name: DP-2
Enabled: 1
Geometry: 0,0,3840x2160
Physical size: 941x529mm
Scale: 1
Refresh Rate: 29981
Adaptive Sync: incapable

Compositing
===========
Compositing is active
Compositing Type: OpenGL
OpenGL vendor string: AMD
OpenGL renderer string: AMD Radeon RX 7900 XT (radeonsi, navi31, LLVM 19.1.7, DRM 3.61, 6.14.1)
OpenGL version string: 4.6 (Core Profile) Mesa 25.0.3
OpenGL platform interface: EGL
OpenGL shading language version string: 4.60
Driver: Unknown
GPU class: Unknown
OpenGL version: 4.6
GLSL version: 4.60
Mesa version: 25.0.3
X server version: 1.24.1
Linux kernel version: 6.14.1
Direct rendering: Requires strict binding: no
Virtual Machine:  no
OpenGL 2 Shaders are used

Loaded Effects:
---------------
shakecursor
screenshot
outputlocator
colorpicker
zoom
screenedge
blur
contrast
sessionquit
logout
login
slidingpopups
windowaperture
slide
fullscreen
frozenapp
squash
fadingpopups
maximize
scale
dialogparent
windowview
tileseditor
overview
highlightwindow
blendchanges
startupfeedback
systembell
screentransform
kscreen

Currently Active Effects:
-------------------------
blur
contrast

Effect Settings:
----------------
shakecursor:

screenshot:

outputlocator:

colorpicker:

zoom:
zoomFactor: 1.2
mousePointer: 0
mouseTracking: 0
focusTrackingEnabled: false
textCaretTrackingEnabled: false
focusDelay: 350
moveFactor: 20
targetZoom: 1

screenedge:

blur:

contrast:

sessionquit:
pluginId: sessionquit
isActiveFullScreenEffect: false

logout:
pluginId: logout
isActiveFullScreenEffect: false

login:
pluginId: login
isActiveFullScreenEffect: false

slidingpopups:
slideInDuration: 200
slideOutDuration: 200

windowaperture:
pluginId: windowaperture
isActiveFullScreenEffect: false

slide:
horizontalGap: 45
verticalGap: 20
slideBackground: true

fullscreen:
pluginId: fullscreen
isActiveFullScreenEffect: false

frozenapp:
pluginId: frozenapp
isActiveFullScreenEffect: false

squash:
pluginId: squash
isActiveFullScreenEffect: false

fadingpopups:
pluginId: fadingpopups
isActiveFullScreenEffect: false

maximize:
pluginId: maximize
isActiveFullScreenEffect: false

scale:
pluginId: scale
isActiveFullScreenEffect: false

dialogparent:
pluginId: dialogparent
isActiveFullScreenEffect: false

windowview:
activeView: 
delegate: 
animationDuration: 300
ignoreMinimized: false
mode: 
partialActivationFactor: 0
gestureInProgress: false
searchText: 
selectedIds: 

tileseditor:
activeView: 
delegate: 
animationDuration: 200

overview:
activeView: 
delegate: 
animationDuration: 300
ignoreMinimized: false
filterWindows: true
organizedGrid: true
overviewPartialActivationFactor: 0
overviewGestureInProgress: false
transitionPartialActivationFactor: 0
transitionGestureInProgress: false
gridPartialActivationFactor: 0
gridGestureInProgress: false
desktopOffset: 
searchText: 

highlightwindow:

blendchanges:

startupfeedback:
type: 1

systembell:

screentransform:

kscreen:


Loaded Plugins:
---------------
BounceKeysPlugin
KeyNotificationPlugin
StickyKeysPlugin
buttonsrebind
eis
krunnerintegration
nightlight
screencast

Available Plugins:
------------------
BounceKeysPlugin
KeyNotificationPlugin
StickyKeysPlugin
buttonsrebind
eis
krunnerintegration
nightlight
screencast
/sys/class/drm/card0-*/edid | hexdump -C
00000000  00 ff ff ff ff ff ff 00  10 ac d4 41 4c 30 36 35  |...........AL065|
00000010  1e 1f 01 04 b5 5e 35 78  3a 8b 5b a4 55 4e 9e 27  |.....^5x:.[.UN.'|
00000020  0e 47 4a a5 4b 00 d1 00  d1 c0 b3 00 a9 40 81 80  |.GJ.K........@..|
00000030  81 00 71 4f e1 c0 4d d0  00 a0 f0 70 3e 80 30 20  |..qO..M....p>.0 |
00000040  35 00 ad 11 32 00 00 1a  00 00 00 ff 00 4a 52 38  |5...2........JR8|
00000050  39 59 38 33 0a 20 20 20  20 20 00 00 00 fc 00 44  |9Y83.     .....D|
00000060  45 4c 4c 20 55 34 33 32  30 51 0a 20 00 00 00 fd  |ELL U4320Q. ....|
00000070  00 1d 4c 1e 8c 3c 01 0a  20 20 20 20 20 20 01 de  |..L..<..      ..|
00000080  02 03 1c f1 4c 10 1f 20  05 14 04 13 12 11 03 02  |....L.. ........|
00000090  01 23 09 1f 07 83 01 00  00 e2 00 6b 4d d0 00 a0  |.#.........kM...|
000000a0  f0 70 3e 80 30 20 35 00  ad 11 32 00 00 1a a3 66  |.p>.0 5...2....f|
000000b0  00 a0 f0 70 1f 80 30 20  35 00 ad 11 32 00 00 1a  |...p..0 5...2...|
000000c0  56 5e 00 a0 a0 a0 29 50  30 20 35 00 ad 11 32 00  |V^....)P0 5...2.|
000000d0  00 1a 11 44 00 a0 80 00  1f 50 30 20 36 00 ad 11  |...D.....P0 6...|
000000e0  32 00 00 1a bf 16 00 a0  80 38 13 40 30 20 3a 00  |2........8.@0 :.|
000000f0  ad 11 32 00 00 1a 00 00  00 00 00 00 00 00 00 12  |..2.............|
00000100
cat /sys/class/drm/card0-*/modes
3840x2160
2560x1440
2048x1280
2048x1152
1920x1200
2048x1080
1920x1080
1920x1080
1920x1080
1920x1080
1920x1080
1920x1080
1600x1200
1680x1050
1280x1024
1280x1024
1280x800
1152x864
1280x720
1280x720
1280x720
1024x768
1024x768
800x600
800x600
720x576
720x576
720x480
720x480
720x480
720x480
640x480
640x480
640x480
640x480
720x400
cat /sys/class/drm/card0-*/status
disconnected
connected
disconnected
disconnected
unknown

So I think all you need to properly use nixos-hardware for most modern AMD GPUs is what you already found:

{
  ...
  imports = [
    ...
    inputs.nixos-hardware.nixosModules.common-gpu-amd
    ...
  ];
}

I don’t think you need to pull in common.amd.gpu directly, since it’s exposed as common-amd-gpu at the module top module level in default.nix which you linked somewhere in your post.

This is working on my AMD GPU systems, one of which is an AMD APU and the other of which has a 7900XTX - though caveat, both have xwindows instead of wayland and I’m running older kernels. The newest kernel I am running anywhere is probably 6.12.19-xanmod.

Unfortunately some cursory searching through nixos options hasn’t shown me anything about declaratively setting refresh rate in wayland, which you can do in x11 - at least you can pass through some options to the x11 config file to enable things like dynamic refresh rate.

What does wlr-randr say? In the past I have had to do wacky things with xrandr to get the correct resolution/refresh rate working in x11, though I have ironed that out with some extra configuration which unfortunately seems to be unavailable in wayland for reasons I don’t have enough brains to comprehend.

1 Like
wlr-randr
compositor doesn't support wlr-output-management-unstable-v1

inputs.nixos-hardware.nixosModules.common-gpu-amd didn’t work, but
nixos-hardware.nixosModules.common-gpu-amd does.

flake.nix

{
  description = "bedHedd flakes";

  inputs = {
    nixpkgs  = {
       url = "github:nixos/nixpkgs/nixos-unstable";
     };

     home-manager = {
       url = "github:nix-community/home-manager";
     };
     nixos-hardware = {
      url = "github:NixOS/nixos-hardware";
    };
  };

  outputs = { self, nixpkgs, nixos-hardware, home-manager, ... }@inputs: {
  
    nixosConfigurations =
      let
        revModule =
          {
              # Let 'nixos-version --json' know about the Git revision
              # of this flake.
              system.configurationRevision = nixpkgs.lib.mkIf (self ? rev) self.rev;
          };
        localNixpkgsModule =
          {
              # For compatibility with other things, puts nixpkgs into NIX_PATH
              environment.etc.nixpkgs.source = nixpkgs;
              nix.nixPath = ["nixpkgs=/etc/nixpkgs"];
          };
      in {
      jade-tiger = nixpkgs.lib.nixosSystem {
        system = "x86_64-linux";
        modules = [ 
          (import ./machines/jade-tiger/configuration.nix)
          # (import ./profiles/dev.nix)
          revModule
          localNixpkgsModule
        ];
        specialArgs = { inherit nixos-hardware home-manager; };
      };
    # use "nixos", or your hostname as the name of the configuration
    # it's a better practice than "default" shown in the video
    #nixosConfigurations.jade-tiger = nixpkgs.lib.nixosSystem {
      #system = "x86_64-linux";
      #specialArgs = {inherit inputs;};
      #modules = [
      #  ./machines/configuration.nix
        # inputs.home-manager.nixosModules.default
      #];
    };
  };
}

configuration.nix

{ config, pkgs, nixos-hardware, home-manager, ... }:

{
  imports =
    [
      nixos-hardware.nixosModules.common-gpu-amd
      #inputs.nixos-hardware.nixosModules.common-gpu-amd
      ./hardware-configuration.nix
      home-manager.nixosModules.home-manager
      ../../modules/home-manager.nix
    ];

  # Bootloader.
  boot.loader.grub.enable = true;
  boot.loader.grub.device = "/dev/nvme0n1";
  boot.loader.grub.useOSProber = true;

  networking.hostName = "jade-tiger"; # Define your hostname.
  # networking.wireless.enable = true;  # Enables wireless support via wpa_supplicant.

  # Configure network proxy if necessary
  # networking.proxy.default = "http://user:password@proxy:port/";
  # networking.proxy.noProxy = "127.0.0.1,localhost,internal.domain";

  # Enable networking
  networking.networkmanager.enable = true;

  nix.settings.experimental-features = [ "nix-command" "flakes"];

  # Set your time zone.
  time.timeZone = "America/Chicago";

  # Select internationalisation properties.
  i18n.defaultLocale = "en_US.UTF-8";

  i18n.extraLocaleSettings = {
    LC_ADDRESS = "en_US.UTF-8";
    LC_IDENTIFICATION = "en_US.UTF-8";
    LC_MEASUREMENT = "en_US.UTF-8";
    LC_MONETARY = "en_US.UTF-8";
    LC_NAME = "en_US.UTF-8";
    LC_NUMERIC = "en_US.UTF-8";
    LC_PAPER = "en_US.UTF-8";
    LC_TELEPHONE = "en_US.UTF-8";
    LC_TIME = "en_US.UTF-8";
  };

  # Enable the X11 windowing system.
  # You can disable this if you're only using the Wayland session.
  services.xserver.enable = true;

  # Enable the KDE Plasma Desktop Environment.
  services.displayManager.sddm.enable = true;
  services.desktopManager.plasma6.enable = true;

  # Configure keymap in X11
  services.xserver.xkb = {
    layout = "us";
    variant = "";
  };

  # Enable CUPS to print documents.
  services.printing.enable = true;

  hardware.graphics = {
    enable = true;
    enable32Bit = true;
  };
  # Enable sound with pipewire.
  hardware.pulseaudio.enable = false;
  security.rtkit.enable = true;
  services.pipewire = {
    enable = true;
    alsa.enable = true;
    alsa.support32Bit = true;
    pulse.enable = true;
    # If you want to use JACK applications, uncomment this
    #jack.enable = true;

    # use the example session manager (no others are packaged yet so this is enabled by default,
    # no need to redefine it in your config for now)
    #media-session.enable = true;
  };

  # Enable touchpad support (enabled default in most desktopManager).
  # services.xserver.libinput.enable = true;

  # Allow unfree packages
  nixpkgs.config.allowUnfree = true;

  # List packages installed in system profile. To search, run:
  # $ nix search wget
  environment.systemPackages = with pkgs; [
    vim # Do not forget to add an editor to edit configuration.nix! The Nano editor is also installed by default.
    git
    wget
    wl-clipboard
    xclip
    wlr-randr 
  ];
  # Some programs need SUID wrappers, can be configured further or are
  # started in user sessions.
  # programs.mtr.enable = true;
  # programs.gnupg.agent = {
  #   enable = true;
  #   enableSSHSupport = true;
  # };

  # List services that you want to enable:

  # Enable the OpenSSH daemon.
  # services.openssh.enable = true;

  users.extraUsers.admin = {
    isNormalUser = true;
    home = "/home/admin";
    extraGroups = [ "wheel" ];
};
  # Open ports in the firewall.
  # networking.firewall.allowedTCPPorts = [ ... ];
  # networking.firewall.allowedUDPPorts = [ ... ];
  # Or disable the firewall altogether.
  # networking.firewall.enable = false;

  # This value determines the NixOS release from which the default
  # settings for stateful data, like file locations and database versions
  # on your system were taken. It‘s perfectly fine and recommended to leave
  # this value at the release version of the first install of this system.
  # Before changing this value read the documentation for this option
  # (e.g. man configuration.nix or on https://nixos.org/nixos/options.html).
  system.stateVersion = "24.11"; # Did you read the comment?


}

Adding a entry to my configuration.nix seemed to fix the issue. I commented out the other connectors so that if there are any issues in the future I can edit them

# machines/machines/jade-tiger/configuration.nix`
# ... stuff before. added this after the boot section
  boot.kernelParams = [ 
    # "video=DP-1:3840x2160@60"
    "video=DP-2:3840x2160@60"
    #"video=DP-3:3840x2160@60"
    #"video=HDMI-A-1:[email protected]"
  ];

based on the output of head /sys/class/drm/*/status

==> /sys/class/drm/card0-DP-1/status <==
disconnected

==> /sys/class/drm/card0-DP-2/status <==
connected

==> /sys/class/drm/card0-DP-3/status <==
disconnected

==> /sys/class/drm/card0-HDMI-A-1/status <==
disconnected

==> /sys/class/drm/card0-Writeback-1/status <==
unknown

I based the instructions off of

https://old.reddit.com/r/NixOS/comments/1e81ait/amd_rx_7900_xt_issues/le45gn3/

https://wiki.nixos.org/wiki/AMD_GPU
based on the wiki’s output for available connectors

Searching “nix os wayland display locked at 30hz”, “nixos 7900 xt display locked at 30hz” or “nixos 7900xt refresh rate locked at 30hz” yielded any helpful results

while using git commit --ammend, I noticed that nano kept getting set as the default editor. I needed to update my home.nix file

With some research on the internet, these posts helped resolve my issue.
These two posts were helpful in informing me that I needed to not only enable a nix parameter, but also an environment variable
https://old.reddit.com/r/NixOS/comments/qc58o4/set_default_editor_to_neovim/hhfabzd/
this post had the home parameters

https://old.reddit.com/r/NixOS/comments/qc58o4/set_default_editor_to_neovim/iww0zfx/

This post was helpful in declaring the required environment variables that other cli tools need.

I used chatgpt to help me generate the needed environment variable declarations for fish. It also suggested some for bash as well

In my case since i had my fish parameters in dotfiles/fish-config, I just added the variable declarations at the end

# dotfiles/fish-config
{ }:
''
# Custom Fish configuration extras
set -g fish_key_bindings fish_default_key_bindings
bind \cc kill-whole-line repaint
bind \cd forward-char

# Add any additional commands here, like initializing zoxide:
# eval (zoxide init fish)

# zoxide init --cmd cd fish | source

function fish_user_key_bindings
  if command -s fzf-share >/dev/null
    source (fzf-share)/key-bindings.fish
  end

  fzf_key_bindings
end

set -gx EDITOR nvim
set -gx VISUAL nvim


''