Trouble setting environment variables in home manager

Hi,

I’m trying to set environment variables for home manager. I have this block in home.nix:

home.sessionVariables = {
    EDITOR = "vim";
    NIXPKGS_ALLOW_UNFREE = 1;
  };

After

home-manager switch --flake .

logout, login:

➜  .dotfiles git:(name) ✗ echo $EDITOR
nano
➜  .dotfiles git:(name) ✗ echo $NIXPKGS_ALLOW_UNFREE

➜  .dotfiles git:(name) ✗

I saw a post on reddit, suggesting this was zsh/shell related, but I have both zsh (default) and bash enabled both in configuration.nix and home.nix, and neither have the variable set. (Also the auto-generated rc files clearly don’t have the settings, so…)

Possibly irrelevant info below:
I don’t want to ask two questions in the same thread, but I’m having a problem of a similar nature, which could be relevant and lead me to discover that the Env variables were not being set. When I try nix shell nixpkgs#opera for example I get the long error about setting allowUnfree to true, even though I have done so (packages.nix is imported to home.nix):

$ grep -r allowUnfree .
./configuration.nix:  nixpkgs.config.allowUnfree = true;
./packages.nix:  nixpkgs.config.allowUnfree = true;

I have no problem installing unfree software declaratively in a module…just not from a shell apparently, which made me think it could be related.

Thanks in advance,
Brian

I think this happens because home.sessionVariables writes variables to ~/.profile, but shells don’t source this by default. However, you can source it with:

This is only necessary for bash as zsh re-sources ~/.zshenv for new instances (see the zsh docs)

  programs.bash = {
    enable = true;

    initExtra = ''
      # include .profile if it exists
      [[ -f ~/.profile ]] && . ~/.profile
    '';
  };

Alternatively, you can set the variables in the shell config. With this, you don’t have to re-login for changes to take effect. You just have to re-source your shell config or open a new terminal:

  programs.zsh = {
    enable = true;
    sessionVariables = {
      EDITOR = "vim";
    };
  };

On another note, some environment variables can be set by home-manager. For example, the defaultEditor option in the following example will automatically set the EDITOR env variable to vim:

  programs.vim = {
    enable = true;
    defaultEditor = true;
  };

Awesome, thank you. I chose the second option for clarity. I was enabling zsh in configuration.nix since it is the default shell, so I just added the variable declarations in home.nix.

Is there any point leaving variable declaration in the “home” block still in addition to the programs block? Seems redundant, but then what is its purpose? Much to learn…

Cheers

A note for other noobs, after doing this I needed to log out and log back in. It was not enough to source .zshrc, nor .profile (which actually points to a file in .nix-profile/etc…) I thought it wasn’t working at first. (I probably could have done su - my-user-name but I didn’t think to do so.)

Let’s take this example:

home-manager
  programs.zsh = {
    enable = true;
    sessionVariables = {
      EDITOR = "nano";
    };
  };
~/.zshenv
# Environment variables
. "/etc/profiles/per-user/user/etc/profile.d/hm-session-vars.sh"

# Only source this once
if [[ -z "$__HM_ZSH_SESS_VARS_SOURCED" ]]; then
  export __HM_ZSH_SESS_VARS_SOURCED=1
  export EDITOR="nano"
fi

When I add HELLO = "world!"; to programs.zsh.sessionVariables then re-build my configs, I see it added to ~/.zshenv. It’s true that you can’t source ~/.zshenv again from the same shell session since env variables are only sourced once with __HM_ZSH_SESS_VARS_SOURCED. However, if you run a new zsh tab/terminal then it should source it without re-login.

You can use home.sessionVariables for variables that all shells will use, then use programs.zsh.sessionVariables for zsh-specific ones, etc…

Actually, where home-manager puts shell variables is different (at least for the version of home-manager I have which is compatible with NixOS 23.11):

  • programs.zsh.sessionVariables~/.zshenv
  • programs.bash.sessionVariables~/.profile
  • home.sessionVariables~/.nix-profile/etc/profile.d/hm-session-vars.sh or /etc/profiles/per-user/user/etc/profile.d/hm-session-vars.sh

So for zsh, you don’t have to manually source ~/.zshenv with programs.zsh.initExtra, but with bash you have to if you want your shell to read the variables without re-login.

Here are some useful links regarding the matter:

I’m grateful for the time you spent writing this. I actually tried to source the hm-session-vars.sh, and profile (same thing really) and it didn’t work until I logged out and in (or launched a new login shell with su -). I had a similar experience installing home manager from the Home Manager Manual. After adding and updating the channel, I needed to log out and in (or su - for a new login shell), in order to run the install command nix-shell '<home-manager>' -A install .

Also, appreciate the link for Z-Shell

1 Like