Can i make reproductible .nix files in non-nixos systems to automatically install packages?

Hello, Vanilla OS 2 is in beta at the moment and when they add nixpkgs support I want to install all of my programs with nixpkgs. As of now on my Arch Linux system I install everything with nix-env -iA ... but I want this to be a .nix file I can deploy anywhere and change whenever I want. I am quite aware I can do that with a bash script but I’m just curious if it’s possible with .nix file. Also if I were to do that with bash and remove entries they actually won’t be removed.

Another question is, if that’s possible, which command should I use to sync packages? nix-env -u ... just updates packages, it doesn’t remove them.

The nixpkgs manual has a guide for that here (anchor link, should take you to the correct section).

While the above avoids most of the severe pitfalls, if you’re going to use nix-env a lot, be aware of its issues:

An approach with fewer footguns would be using home-manager and its home.packages option instead. Also gives you convenient access to the home-manager modules if you ever end up wanting to use them.

Another question is, if that’s possible, which command should I use to sync packages? nix-env -u ... just updates packages, it doesn’t remove them.

I don’t really understand what you mean by this?

Ah! I completely forgot about home-manager even though I used Nixos before haha. It’s great that I can use it with other distros as well.

My second question was, can I remove packages with the same command as well, which home-manager build can handle so, no worries there!

However I kind of hit a wall, I put pkgs.hello to home.nix in fact build built it as well but when I type hello to my terminal it doesn’t show up, same with any other package.

Output of home-manager packages is:

home-manager packages

If I’m not wrong this is where I should see the program hello

Did you follow step 4 of the standalone installation instructions? Sounds like the typical result of forgetting to source the home-manager env.

If you do not plan on having Home Manager manage your shell configuration then you must source the


file in your shell configuration. Alternatively source


when managing home configuration together with system configuration.

This file can be sourced directly by POSIX.2-like shells such as Bash or Z shell. Fish users can use utilities such as foreign-env or babelfish.

For example, if you use Bash then add

. "$HOME/.nix-profile/etc/profile.d/"

to your ~/.profile file.

I did source $HOME/.nix-profile/etc/profile.d/ in my zsh terminal because i don’t want home manager to manage my zsh configuration. I haven’t done anything else since they are for managing shell if I understood correctly.

No, the exact opposite. If you don’t want home-manager to manage your shell configuration, it won’t be able to source that script for you, and as a result a whole bunch of environment variables that your configuration intends to set won’t be set. Among them, importantly, is $PATH, so none of the things added to home.packages will actually be “installed”.

To confirm that is the issue, just source that path in a shell, and in the same shell check if the packages you installed are there. If they are, add that line to ~/.profile (or ~/.zshrc or ~/.zsh_profile or whatever, depending on the exact setup your shell init files have) to make it permanent.

If you did let home-manager manage your shell configuration, it would just source that file in your ~/.profile without you having to manually add that yourself, which is why that’s mentioned in the docs.

Ok so, you want me to source $HOME/.nix-profile/etc/profile.d/ or source /etc/profiles/per-user/$USER/etc/profile.d/ in my zsh terminal? Because I already did the former and it didn’t work.

Also can I use ~/.zshrc or ~/.zshenv instead of ~/.profile?

The former is a symlink to the latter (~/.nix-profile/etc/profiles/per-user/$USER/profile), so that won’t make a difference.

Yep, the home-manager module uses ~/.zshenv in fact:

# Environment variables
. "/etc/profiles/per-user/tlater/etc/profile.d/"

# Only source this once
if [[ -z "$__HM_ZSH_SESS_VARS_SOURCED" ]]; then


export ZDOTDIR=$HOME/.config/zsh

Hm, ok, what is in your $PATH? What is in your home-manager config? How did you activate it?

echo $PATH:



{ config, pkgs, ... }:

  # Home Manager needs a bit of information about you and the paths it should
  # manage.
  home.username = "user";
  home.homeDirectory = "/home/user";

  # This value determines the Home Manager release that your configuration is
  # compatible with. This helps avoid breakage when a new Home Manager release
  # introduces backwards incompatible changes.
  # You should not change this value, even if you update Home Manager. If you do
  # want to update the value, then make sure to first check the Home Manager
  # release notes.
  home.stateVersion = "23.11"; # Please read the comment before changing.

  # The home.packages option allows you to install Nix packages into your
  # environment.
  home.packages = [
    # # Adds the 'hello' command to your environment. It prints a friendly
    # # "Hello, world!" when run.

    # # It is sometimes useful to fine-tune packages, for example, by applying
    # # overrides. You can do that directly here, just don't forget the
    # # parentheses. Maybe you want to install Nerd Fonts with a limited number of
    # # fonts?
    # (pkgs.nerdfonts.override { fonts = [ "FantasqueSansMono" ]; })

    # # You can also create simple shell scripts directly inside your
    # # configuration. For example, this adds a command 'my-hello' to your
    # # environment:
    # (pkgs.writeShellScriptBin "my-hello" ''
    #   echo "Hello, ${config.home.username}!"
    # '')

  # Home Manager is pretty good at managing dotfiles. The primary way to manage
  # plain files is through 'home.file'.
  home.file = {
    # # Building this configuration will create a copy of 'dotfiles/screenrc' in
    # # the Nix store. Activating the configuration will then make '~/.screenrc' a
    # # symlink to the Nix store copy.
    # ".screenrc".source = dotfiles/screenrc;

    # # You can also set the file content immediately.
    # ".gradle/".text = ''
    #   org.gradle.console=verbose
    #   org.gradle.daemon.idletimeout=3600000
    # '';

  # Home Manager can also manage your environment variables through
  # 'home.sessionVariables'. If you don't want to manage your shell through Home
  # Manager then you have to manually source '' located at
  # either
  #  ~/.nix-profile/etc/profile.d/
  # or
  #  ~/.local/state/nix/profiles/profile/etc/profile.d/
  # or
  #  /etc/profiles/per-user/alova/etc/profile.d/
  home.sessionVariables = {
    # EDITOR = "emacs";

  # Let Home Manager install and manage itself.
  programs.home-manager.enable = true;

I activated it with:

nix-channel --add home-manager
nix-channel --update
nix-shell '<home-manager>' -A install
home-manager build

That only makes a result directory in your current directory that contains the files that would make up your home profile, it doesn’t install anything. Use home-manager switch.

Bless you! I always do the dumbest mistakes, thank you for everything.
Just as a extra question, these are all being sandboxed right?

Nix doesn’t do any sandboxing by default. Installing stuff with nix-env doesn’t sandbox anything either.

Some things might use buildUserFhs to make them work correctly under nix’ non-fhs paradigm, which will also use cgroups, but the intention for that is explicitly not sandboxing, so shouldn’t be relied on for security (in fairness, this is also true for flatpaks). This is absolutely not the norm though, most applications just run as if they were installed normally.

in here it says sandboxing is possible and is the default. That really was one of the biggest reasons I wanted to use Nix. Is this manual outdated?

No, that’s build sandboxing. When the software is built that is done in a sandbox to prevent the environment affecting your build outputs. The actual outputs are just the same as any old distro package, except that they do not adhere to the fhs standard.

So, when you run, say, nix-shell -p neovim --command vim or whatever, that vim will have full access to anything your user has access to. This is unlike flatpaks, where specific paths are/can be excluded, various kernel APIs are inaccessible, etc., and in some cases a protocol is used to communicate with your desktop environment to ask you to permit access.

Ok got it, thank you. I set the issue as solved, sorry for taking a large chunk of your time :slight_smile: