I'm going to preempt this with anything not explicitly forbidden is allowed, lest this come off as "you holding it wrong".
Using the CLI to add/remove package is considered kind of an antipattern in nix. The correct way to write a fair bit of Nix (the language) to install and configure things. That then can be versioned, forked, etc.
There are a lot of really cool parts of Nix, but they're under a ball of rough edges.
I think there are two distinct arguments against nix-env:
1. Imperative package management is evil
2. The package name-based interface used by nix-env is evil
I don't ascribe to (1); I quite like installing things "the old-fashioned way." Saying "install this thing" is a very nice, familiar UX. (Even if under the hood you implement that as "add this to my declared list of packages and then rebuild the world," I would still rather run a single command than edit a text file and then run a command most of the time.)
But I think that (2) is true, for the reasons outlined in that post. I have never really heard anyone defending name-based operations; the universal consensus is that it was a bad decision made decades ago. It's something that you can avoid if you are aware of the problem, but it is still, for backwards compatibility, the "default" way that nix-env works. (And although you can install packages the "right" way, you have to resort to name-based operations if you use nix-env's built-in uninstall or upgrade commands, which is also very confusing.)
nix-env -irf is neither (1) imperative nor (2) name-based; I use it as a way to implement my home-rolled declarative package management solution linked in the sibling, taking advantage of the fact that nix-env is okay at building profiles already. The flags literally mean "uninstall everything, then install everything that is listed in this file," but what that translates to is "create a new profile with the contents of this file, disregarding the contents of the current profile."
I'm finding nix-env to be great! I do not understand why nix offers a command and a package index, but then advises not to use it.
If people aren't supposed to use nix-env, why don't nix put a huge deprecated notice on every invocation and delete the nix-env command itself from nix?
Nix devs seem focused on improving the ergonomics of the new command line, but it’d probably take time to flesh out the details. In the meantime, I think specifying the package source is a reasonable tradeoff given the features it enables.
I also suspect that keeping the package specification the same between installation and uninstallation time is harder than it might look, though. By its nature, Nix identifies packages by the contents of their definition. “nixpkgs#ripgrep” is merely a pointer to the current ripgrep package definition in the Nixpkgs repository. Therefore, “nixpkgs#ripgrep” will likely not point to the same package at the time of uninstallation.
One idea, if the customers tend to be NixOS enjoyers, would be to put the tool in Nix Packages and then use nix-shell for them to access it.
Perhaps the nix packages configuration could reference a script with everything properly debugged and then the snake can eat its own tail.
It seems like a provisioner to install and configure stuff, in which case one obvious method to install is copy pasting bash code. Have we really reached an era where folks expect to use CLI tools without using a CLI?
Can nixpkgs install from brew? Maybe that’s the answer, use the annoying stuff and wrap it with something to make it less annoying. Or, you could wrap your CLI with Tauri and install with Cargo. Might be more robust but not in the comfort zone of a nix shop.
I really want to love Nix and have installed it multiple times. It's non-standard file layout gets me every time though. Something as simple as `#!/bin/bash` not working is problematic for me. I also find that trying to install anything not included in the Nix package manager is pretty much impossible (building from source...).
Do you have a link to where I can read about using Nix as purely a package manager? Or a minimal example showing how a Nix config looks if used in this manner?
I'm not sure why you think there is any 'config' involved. Perhaps you're conflating Nix the package manager with NixOS? Nix is many things, but it's also just a package manager like any other. For example:
nix profile install nixpkgs#vim # installs a package into your environment
nix shell nixpkgs#binwalk nixpkgs#vim # drops you into a shell with the given packages
nix run nixpkgs#firefox # runs the mainProgram of the given package
A couple of things to note:
The aforementioned commands are the "experimental" Nix 2.4 CLI commands that integrate with Nix Flakes. They are only experimental in name though, their status of being experimental being sort of a meme at this point. I recommend using these new commands (you can opt in by supplying a command-line flag or by tweaking the package manager config).
Packages that are not in active use (e.g. packages that you've referred to in 'nix shell' or 'nix run' invocations that are not installed using 'nix profile') are due for garbage collection. The garbage collection settings can be configured (either through NixOS, home-manager or the package manager's standalone configuration). The garbage collection can also be triggred manually. This makes experimenting with programs that you don't necessarily want to keep a joy.
The 'nixpkgs' in the aforementioned invocations is a default input that is set during installation. It refers to the nixpkgs package archive's flake's master branch's latest revision (https://github.com/nixos/nixpkgs). The available inputs are configurable (again, either through NixOS, home-manager or the package manager's standalone configuration).
I use it, it's quite cool, I did need to patch it to fit my needs, but it makes it easy package anything.
I wish though that it would expose the mechanism as nix derivation instead of CLI command (I eventually figured how to do it, but feels a bit hacky to me)
It's not so bad actually. To add a new package there's only two files you have to touch, add a new default.nix somewhere in the pkgs/ tree and add your package to pkgs/top-level/all-packages.nix. Looking at any of the 60,000 packages in Nixpkgs should give one an idea of what to write.
I like to use nix-env (or more often, now, `nix profile`) for a persistence level in between nix-shell and really adding something to my home-manager or NixOS config. I let my profile build up 10-20 things installed, then every few weeks I decide what belongs in my declared config and uninstall everything in the profile.
Imo entirely removing imperative package management would be a mistake, although imperatively managing a file that gets sourced in your declarative config (a bit like /var/dpkg/selections on ol' Debian) instead of putting the whole profile manifest in the Nix store and leaving it at that would be better.
For installing a package, you have to specify the package repository. For uninstalling, you don't because you're operating against a separate repository containing locally installed packages. This should be the same for the new CLI too.
Looking at the manual[1], instead of:
nix profile remove nixpkgs#ripgrep
You'd probably need to run:
nix profile remove packages.x86_64-linux.ripgrep
For searching packages,
nix search nixpkgs ripgrep
is faster than
nix-env -qaP ripgrep
But I find the online search UI[2] to be far more superior.
To be clear, Nix's CLI syntax is what it is because of the following requirements:
* Provide the ability to create a new package by extending an existing package definition programatically
* Provide the ability to have multiple variations of similar packages
To satisfy those requirements, you need a way to uniquely specify packages by its precise location of its definition. It does not interact well with apt's model of having a central package repository assign names for every known package.
> "today I want to install a package on my computer and revel in my extreme knowledge of how my package manager works"
Yeah, I would really like to see `nix-env -i` recommended far less often, or at least with the caveat that this should only be for testing packages at the most. I still haven't found a good use case for it personally.
One of the big wins for Nix is its declarative nature (especially for reproducibility) and installing packages in an imperative manner like this just seems to put folks back in the same position as using pacman or apt-get. Please correct me if I'm wrong Nix-ers.
Having used NixOS as the main OS on my personal laptop for the past year or two (and loving it), I've only used `nix-env -i` to install a package once, and immediately regretted it after trying to add a different version of the same package to my main configuration files. This resulted in a conflict, which from memory required me to force reinstall the package again via `nix-env` but specify a lower priority so that it could be replaced automatically when enabling the package via my configuration files... A really strange experience that re-affirmed that nix-env is at least not for me.
For testing packages, I would always recommend `nix-shell -p <package>` as a preferred option. Just type `exit` and then you've left the shell, it's no longer in your PATH and there's no risk of conflicts.
It sucks that you ran into this, but also totally understandable. I think generally the community would consider the nix-env approach of installing and updating packakges an anti-pattern these days, but this certainly isn't obvious when reading through the docs.
The problem is that /opt/nix isn’t safe from the OS and Nix is explicitly software that doesn’t follow the FHS so it makes no sense to install it in a prefix.
One could argue the same for any package-oriented system, from Red Hat to Solaris to Debian/Ubuntu ("only use packages"). The reality is quite different, and it's always been different. I'm unaware of any environment that's used packages for every aspect of system management, and Nix isn't going to change that.
Moreover, there's nothing stopping a Nix package author from writing a post-install script that causes state changes to be made out of bounds. The package manager isn't going to notice, and it's not going to clean it up at deinstallation time.
> Actually, I already find it strand that you can call the package manager like that, shouldn't there be a declaration of the packages I want somewhere, should I not add the package that list (maybe a Yaml, like my docker-compose.yaml?) then ask Nix to make the installation consistent with the declaration?
Yes, I completely avoid 'nix-env' for that reason. It maintains a bunch of symlinks behind-the-scenes, but the 'nix-env' command itself is imperative.
If you use NixOS, the config option 'env.systemPackages' specifies which programs to install. This can be declared in the /etc/nixos/configuration.nix file. There are similar approaches when using Nix on non-NixOS systems (e.g. using the 'buildEnv' function from Nixpkgs to combine multiple programs into a single derivation/package, and install that)
My tip: don't use nix-env to install packages like it's Aptitude or Pacman, use `nix run` if you need a package temporarily, home-manager if you need a user-level package permanently, or just straight up change the configuration.nix to include the package as a system-wide one.
If you use nix-env you're just polluting your environment in an imperative way and that is pretty much going against Nix' declarative nature.
Using the CLI to add/remove package is considered kind of an antipattern in nix. The correct way to write a fair bit of Nix (the language) to install and configure things. That then can be versioned, forked, etc.
There are a lot of really cool parts of Nix, but they're under a ball of rough edges.
reply