Oh yeah, you can if you do it properly.
I’ve a packages.nix
module where, alongside declaring the packages I want to pull from stable
and nixpkgs-unstable
, I define this variable pkgsUnstable
:
pkgsUnstable = import inputs.nixpkgs-unstable {
inherit system;
config = {
allowUnfree = true;
};
};
That allows me to define groups of attribute sets for the packages I want to install from either OR both channels, this way:
packagesBaseline =
with pkgs;
[
# Nix - Security
vulnix # NixOS vulnerability scanner :: https://github.com/nix-community/vulnix
# Networking
httping # Ping with HTTP requests :: https://vanheusden.com/httping
# Python
python312 # High-level dynamically-typed programming language :: https://www.python.org
python312Packages.ipython # IPython: Productive Interactive Computing :: https://ipython.org/
# Storage
nfstrace # NFS and CIFS tracing/monitoring/capturing/analyzing tool :: NFS and CIFS tracing/monitoring/capturing/analyzing tool
]
++ (with pkgsUnstable; [
# Misc
at
bat
broot # Interactive tree view, a fuzzy search, a balanced BFS descent and customizable commands :: https://dystroy.org/broot/
chezmoi
...
...
]);
And do:
environment.systemPackages =
[ ] # Start with an empty list or your base packages
++ lib.optionals cfg.baseline packagesBaseline
++ lib.optionals cfg.cli._all (builtins.concatLists (builtins.attrValues packagesCli))
++ lib.optionals cfg.cli.ai packagesCli.ai
++ lib.optionals cfg.cli.backup packagesCli.backup
++ lib.optionals cfg.cli.cloudNativeTools packagesCli.cloudNativeTools
++ lib.optionals cfg.cli.comms packagesCli.comms
++ lib.optionals cfg.cli.databases packagesCli.databases
++ lib.optionals cfg.cli.misc packagesCli.misc # TODO_ properly categorize the packages
++ lib.optionals cfg.cli.multimedia packagesCli.multimedia
++ lib.optionals cfg.cli.programming packagesCli.programming
++ lib.optionals cfg.cli.secrets packagesCli.secrets
++ lib.optionals cfg.cli.security packagesCli.security
++ lib.optionals cfg.cli.vcs packagesCli.vcs
++ lib.optionals cfg.cli.web packagesCli.web
++ lib.optionals cfg.gui packagesGui
++ lib.optionals cfg.guiShell.kde packagesGuiShell.kde
++ lib.optionals cfg.nvidia packagesNvidia
++ config.mySystem.myOptions.packages.modulePackages; # Add packages contributed by other modules
To assemble the final list of packages to install from both channels, I created several options that allow me to easily toggle what set of packages I want to install on each different host–each host has a profile where you can choose not only what packages to install, but also configure everything else.
There’s a bunch of community flakes I rely on too, so properly defining both channels in the flake, like this:
inputs = {
nixpkgs.url = "nixpkgs/nixos-24.11"; # NixOS release channel
nixpkgs-unstable.url = "nixpkgs/nixos-unstable"; # The unstable release channel to allow for fresher packages
}
It’s super important to configure them, e.g.:
# Snapd support for NixOS
nix-snapd = {
inputs.nixpkgs.follows = "nixpkgs-unstable";
url = "github:nix-community/nix-snapd";
};
# A Neovim configuration system for Nix
nixvim = {
inputs.nixpkgs.follows = "nixpkgs";
url = "github:nix-community/nixvim/nixos-24.11";
};
Notice how the nix-snapd
flake input follows nixpkgs-unstable
and nixvim
follows the stable channel.
HTH