Installing only a single package from `unstable`

Hi there. I manage some NixOS machines, which are pinned to a particular stable branch from 2019, and I’m fine with this.

However, the version of certbot that this branch offers is 0.31.0, while unstable has 1.0.0. I’d like to upgrade, and do so via the usual environment.systemPackages list. However, I don’t want to update the whole channel (thus bumping everything else on the system), just certbot.

Is this possible? Please and thank you.

4 Likes

I have been doing it this way:

  1. Add the channel as root
sudo nix-channel --add https://nixos.org/channels/nixos-unstable nixos-unstable
sudo nix-channel --update
  1. Edit the nix file with your environment.systemPackages something like this:
let
  unstable = import <nixos-unstable> { config = { allowUnfree = true; }; };
in {
  environment.systemPackages = with pkgs; [
    wget
    vim
    unstable.ffmpeg
  ];
}

It is covered in one of the docs but I can never find it when I need it.

16 Likes

@dalto Is there a way to add the unstable nix channel within one’s configuration.nix?

3 Likes

@dalto Is there a way to add the unstable nix channel within one’s configuration.nix ?

@fosskers You had a perfectly valid question there, I see no reason to withdraw it. The answer can be found elsewhere, but it is good to have multiple references for visibility. Unfortunately the prominent NixOS Wiki search result does not even feature it. Really it is a combination of that and the example on pinning nixpkgs:

# configuration.nix
{ config, pkgs, ... }:
let
  unstable = import
    (builtins.fetchTarball https://github.com/nixos/nixpkgs/tarball/<branch or commit>)
    # reuse the current configuration
    { config = config.nixpkgs.config; };
in
{
  environment.systemPackages = with pkgs; [
    nginx
    unstable.certbot
  ];
}

You should of course specify a hash, and probably a derivation name, my example is simplified for readability. Check the Nix manual for builtin function specs.

12 Likes

Unfortunately, the above requires root.

To do this as user / without root-permissions, to install e.g. vim from unstable:

nix-channel --add https://nixos.org/channels/nixos-unstable nixos-unstable
nix-channel --update
nix-env -f .nix-defexpr/channels/nixos-unstable -iA vim

Is there a way to

  • pin a package?
  • make this simpler, e.g. something like
    nix-env --channel nixos-unstable -iA vim ?

Maybe nix-env -f '<nixos-unstable>' -iA vim or nix-env -iA nixos-unstable.vim

To install packages declaratively as a regular user you can use home-manager. The respective code in home.nix would look exactly the same, except replace environment.systemPackages with home.packages.

3 Likes

To install from a channel imperatively:

nix-env -f channel:nixpkgs-unstable -iA vim

Can this be done for packages that require modules?

Is there a way to pin a single module + it’s realated package to unstable version?

I’ve got a feeling you cant.

Since nobody has mentioned it, for flake users this is substantially simpler since one can declare multiple versions of nixpkgs as an input. Then one can use an overlay to place the contents of a single package from nixos-unstable into the base system.

Also, @nixinator this isn’t possible by default, but one can easily pull a module from unstable nixpkgs manually, while adding the old version to disabledModules.

1 Like

do you have a handy example i could take a peek at ?

I have a (not so minimal) example available in my DevOS project.

To fully understand what’s going on you’ll want to look at the logic, and the place where overrides are declared.

The reason this isn’t minimal is because it tries to automatically disable a module that is pulled from the override nixpkgs input.

To do it manually in stable nix one would simply add the module name relative to the nixpkgs/nixos/modules directory to disabledModules, then import the alternative version from a reference to another nixpkgs:

# some NixOS module
let
  someOtherNixpkgs = builtins.fetchurl # some nixpkgs url
  ;
in
{
  # if your NIX_PATH contains another nixpkgs reference, 
  # you can use the <some_nixpkgs/nixos/modules/...> syntax instead
  imports = [ "${someOtherNixpkgs}/nixos/modules/programs/steam.nix" ];
  disabledModules = [  "programs/steam.nix" ];
}
3 Likes

if the app u trying to install is only for your user only you dont need to make sperate config…what you need is

  1. add the unstable channel :
    _>nix-channel --add nixos-unstable release nixos-24.05pre582649.d934204a0f8d [theChannelName]

  2. update the channel :
    _>nix-channel --update

  3. install the app using channel name :
    _>nix-env -iA [theChannelName].yourApp

dont use sudo if you want the app only for your current login user… :slightly_smiling_face:

I was using overlay that basically look like:

self: super:
let
  cherryPick = pkg: pkg.override (origArgs: builtins.intersectAttrs origArgs self);
  nixpkgs-unstable = import <nixpkgs-unstable> {};
in
{
  zig-unstable = assert (! super ? zig-unstable); (cherryPick nixpkgs-unstable.zig).override {
    llvmPackages = self.llvmPackages_11;
  };
}

Unfortunately zig-unstable have to be re-built, but with this it only depends on main system packages without pulling in parallel tree from unstable.

Thank you. This worked unbelievably well in my case.

3 Likes

How do I configure the package this way after I install it? In this context, I’m trying to configure the new helix-editor.

...
  [
    unstable.helix
  ];
...
  programs.helix = {
  languages = [

After this package is installed, the package can’t be configured.

The configuration settings come from modules, not packages. The NixOS module system is much more involved, but you can substitute out a module from an old nixpkgs with one from a new nixpkgs: NixOS 23.11 manual | Nix & NixOS

This is much less likely to work properly, after all any differences in underlying modules could break things quite a bit, but if it’s a completely new module and for something relatively simple as in your case it will usually be fine.

The Helix module exposes a package option (see here), remove unstable.helix from home.packages then do:

 programs.helix = {
+  package = unstable.helix;
   languages = [
1 Like

Is there an equivalent workaround like this on a flake?

3 Likes

Where do you get the hash and derivation name from?
If you have the time, could you provide an example including hash and derivation name?