How to use nixos-unstable for one machine and stable for the other one with a single flake.nix

Background

I use a single flake for my machines. Currently, both my laptop and my (under-construction) server run on nixos-unstable. I realized though that soon I may have to do overlays (or overrides, these stuff confuse me) to keep the server updated even if a package is broken and I probably will have to adjact to breaking changes very often compared to a stable configuration. It’s not a big issue for my laptop, but I want the server to be secure and somwhat more stable.
Thus I decided to use nixos-unstable for my laptop and nixos stable for my server.
This is my flake currently: https://codeberg.org/BlastboomStrice/dotfiles/src/commit/d703e4c583c5d94236ed2c046ae823720c0f0b63/.config/nixos-config/flake.nix
I tried to remove any anti-patterns, like setting the system variable or the pkgs variable.

Here is the flake pasted:

Flake.nix
{
  description = "Nixos-unstable config flake (with home-manager, spicetify-nix, sops-nix)";

  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";

    home-manager = {
      url = "github:nix-community/home-manager";
      inputs.nixpkgs.follows = "nixpkgs";
    };

    spicetify-nix = {
      url = "github:Gerg-L/spicetify-nix";
      inputs.nixpkgs.follows = "nixpkgs";
    };

    sops-nix = {
      url = "github:Mic92/sops-nix";
      inputs.nixpkgs.follows = "nixpkgs";
    };

    nix-flatpak = {
      url = "github:gmodena/nix-flatpak/?ref=latest"; # Use github:gmodena/nix-flatpak/?ref=<tag> to pin releases.
      # warning: input 'nix-flatpak' has an override for a non-existent input 'nixpkgs'
      # inputs.nixpkgs.follows = "nixpkgs"; # unecessary
    };
  };

  outputs =
    {
      self,
      nixpkgs,
      ...
    }@inputs:
    # OR
    # inputs@{ self, nixpkgs, ... }:
    {
      nixosConfigurations = {
        # Per host/device config:
        # $hostname = nixpkgs.lib.nixosSystem { ... };
        # nixos = nixpkgs.lib.nixosSystem { ... }; would activate the configs in ./hosts/default without .#nixos or .#default and the end of the path
        # https://discourse.nixos.org/t/flake-path-does-not-provide-attribute-packages-x86-64-linux/20700/

        # Dell laptop (main device) - BEGIN
        nixos-main = nixpkgs.lib.nixosSystem {
          # system = "x86_64-linux";  # states system architecture to target # already mentioned in hardware-configuration.nix
          specialArgs = { inherit inputs; }; # passes `inputs` to all the modules in the list (it isn't automatically inherited)
          modules = [
            # Anything that is placed here becomes available to the whole configuration, regardless of what file/module I import in configuration.nix etc.

            # configuration.nix
            # Location of configuration.nix for nixos-main
            ./hosts/nixos-main/configuration.nix

            # home-manager:
            inputs.home-manager.nixosModules.home-manager

            # Spicetify for configuration.nix (For NixOS)
            inputs.spicetify-nix.nixosModules.default

            # Flatpak - declarative - convergent mode approach
            inputs.nix-flatpak.nixosModules.nix-flatpak

            # Options can be set **anywhere** in modules[], **grouped or not**, as long as they are enlcosed by {}
            {
              home-manager = {
                useGlobalPkgs = true; # Needed, not sure why
                useUserPackages = true; # Needed, not sure why
                # Location of home.nix for nixos-main
                # Replace users.<USERNAME> with your actual username
                users.bs = import ./hosts/nixos-main/home.nix;
              };

              # Already set by `specialArgs = { inherit inputs; };` above:
              # home-manager.extraSpecialArgs = { inherit inputs; };
              # This is specifically for home-manager, we need another similar declaration for configuration.nix
              # OR (applies to all modules in the list)
              # _module.args = { inherit inputs; };
            }

          ];
        };
        # Dell laptop (main device) - END

        # Server - BEGIN
        nixos-base = nixpkgs.lib.nixosSystem {
          # system = "x86_64-linux";  # states system architecture to target # already mentioned in hardware-configuration.nix
          specialArgs = { inherit inputs; }; # passes `inputs` to all the modules in the list (it isn't automatically inherited)
          modules = [
            # Anything that is placed here becomes available to the whole configuration, regardless of what file/module I import in configuration.nix etc.

            # configuration.nix
            # Location of configuration.nix for nixos-base
            ./hosts/nixos-base/configuration.nix

            # home-manager:
            inputs.home-manager.nixosModules.home-manager

            # Spicetify for configuration.nix (For NixOS)
            inputs.spicetify-nix.nixosModules.default

            # Sops nix for configuration.nix (For NixOS)
            inputs.sops-nix.nixosModules.sops

            # Flatpak - declarative - convergent mode approach
            inputs.nix-flatpak.nixosModules.nix-flatpak

            # Options can be set **anywhere** in modules[], **grouped or not**, as long as they are enlcosed by {}
            {
              home-manager = {
                useGlobalPkgs = true; # Needed, not sure why
                useUserPackages = true; # Needed, not sure why
                # Location of home.nix for nixos-base
                # Replace users.<USERNAME> with your actual username
                users.base = import ./hosts/nixos-base/home.nix;
              };
            }

          ];
        };
        # Server - END

      };
    };
}

# ORIGINAL-BEGIN
# {
#   description = "Nixos config flake";
#
#   inputs = {
#     nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
#
#     home-manager = {
#       url = "github:nix-community/home-manager";
#       inputs.nixpkgs.follows = "nixpkgs";
#     };
#   };
#
#   outputs = { self, nixpkgs, ... }@inputs:
#     let
#       system = "x86_64-linux";
#       pkgs = nixpkgs.legacyPackages.${system};
#     in
#     {
#
#       #default config (check the .default)
#       nixosConfigurations.default = nixpkgs.lib.nixosSystem {
#         specialArgs = {inherit inputs;};
#         modules = [
#           ./hosts/default/configuration.nix
#           #inputs.home-manager.nixosModules.default
#         ];
#       };
#
#     };
# }
# ORIGINAL-END

Issue

My issue is how to exactly define in the flake that I want the laptop to use unstable and the server to use stable? I want the nixpkgs input to be the unstable branch for the laptop and the stable branch for the server. It’s not a big issue if other inputs keep using unstable, I’m ok with that.

What do the docs say

I found 2 sources that may be of help:

Things I’ve tried

I’ve come up with a new flake version, but I didn’t test it, because I don’t want to ruin the server or something. I know switching from unstable to stable almost certainly means that there are gonna be issues and I might need to wipe my server, but that’s ok, as it is still under construction.

The changes I made are:

  • I added the stable branch to a nixpkgs-stable input
  • I now pass all inputs explicitly to the output arguments (I’m not sure I use the terms correctly here)
    • I guess this means I can remove the inputs. prefix of each module listed in modules = [ ];
  • I no longer do specialArgs = { inherit inputs; };, but I let it inherit only inputs that I want and for nixpkgs I pass nixpkgs = nixpkgs-stable; to specialArgs

The actual file diff is this:

flake.nix - diff
--- -	2026-08-05 18:52:51.247593114 +0300
+++ ~/dotfiles/.config/nixos-config/flake.nix	2026-08-05 18:52:48.778421972 +0300
@@ -24,19 +24,12 @@
       # warning: input 'nix-flatpak' has an override for a non-existent input 'nixpkgs'
       # inputs.nixpkgs.follows = "nixpkgs"; # unecessary
     };
+
+    # Stable versions
+    nixpkgs-stable.url = "github:nixos/nixpkgs/release-26.05";
   };
 
   outputs =
     {
       self,
       nixpkgs,
+      home-manager,
+      sops-nix,
+      nix-flatpak,
+      nixpkgs-stable,
       ...
     }@inputs:
     # OR
@@ -92,13 +85,7 @@
         # Server - BEGIN
         nixos-base = nixpkgs.lib.nixosSystem {
           # system = "x86_64-linux";  # states system architecture to target # already mentioned in hardware-configuration.nix
+          # specialArgs = { inherit inputs; }; # passes `inputs` to all the modules in the list (it isn't automatically inherited)
+          specialArgs = {
+            inherit home-manager;
+            inherit sops-nix;
+            inherit nix-flatpak;
+            nixpkgs = nixpkgs-stable;
+          };
-          specialArgs = { inherit inputs; }; # passes `inputs` to all the modules in the list (it isn't automatically inherited)
           modules = [
             # Anything that is placed here becomes available to the whole configuration, regardless of what file/module I import in configuration.nix etc.

You need to use nixpkgs-stable.lib.nixosSystem if you want to use nixpkgs-stable.

3 Likes

So the only change I need to do is this?

--- -	2026-08-05 19:07:53.957057869 +0300
+++ ~/dotfiles/.config/nixos-config/flake.nix	2026-08-05 19:07:51.258570439 +0300
@@ -24,16 +24,12 @@
       # warning: input 'nix-flatpak' has an override for a non-existent input 'nixpkgs'
       # inputs.nixpkgs.follows = "nixpkgs"; # unecessary
     };
+
+    # Stable versions
+    nixpkgs-stable.url = "github:nixos/nixpkgs/release-26.05";
   };
 
   outputs =
     {
       self,
       nixpkgs,
+      nixpkgs-stable,
       ...
     }@inputs:
     # OR
@@ -87,7 +83,7 @@
         # Dell laptop (main device) - END
 
         # Server - BEGIN
+        nixos-base = nixpkgs-stable.lib.nixosSystem {
-        nixos-base = nixpkgs.lib.nixosSystem {
           # system = "x86_64-linux";  # states system architecture to target # already mentioned in hardware-configuration.nix
           specialArgs = { inherit inputs; }; # passes `inputs` to all the modules in the list (it isn't automatically inherited)
           modules = [

Essentially:

  1. Add branch for nixpkgs-stable to inputs
  2. Add nixpkgs-stable input to output arguments
  3. Switch from nixpkgs.lib.nixosSystem to nixpkgs-stable.lib.nixosSystem

specialArgs = { inherit inputs; }; feels like it may mess up the config, or not, hmm

Do not use release-*, use nixos-*. Release is for stable as master is for unstable

4 Likes

Good catch:)

So, final version:

--- -	2026-08-05 19:07:53.957057869 +0300
+++ ~/dotfiles/.config/nixos-config/flake.nix	2026-08-05 19:07:51.258570439 +0300
@@ -24,16 +24,12 @@
       # warning: input 'nix-flatpak' has an override for a non-existent input 'nixpkgs'
       # inputs.nixpkgs.follows = "nixpkgs"; # unecessary
     };
+
+    # Stable versions
+    nixpkgs-stable.url = "github:nixos/nixpkgs/nixos-26.05";
   };
 
   outputs =
     {
       self,
       nixpkgs,
+      nixpkgs-stable,
       ...
     }@inputs:
     # OR
@@ -87,7 +83,7 @@
         # Dell laptop (main device) - END
 
         # Server - BEGIN
+        nixos-base = nixpkgs-stable.lib.nixosSystem {
-        nixos-base = nixpkgs.lib.nixosSystem {
           # system = "x86_64-linux";  # states system architecture to target # already mentioned in hardware-configuration.nix
           specialArgs = { inherit inputs; }; # passes `inputs` to all the modules in the list (it isn't automatically inherited)
           modules = [

I realize that in my configuration.nix I reference nixpkgs, like nixpkgs.config, so I guess I should also do

+          specialArgs = {
+            inherit home-manager;
+            inherit sops-nix;
+            inherit nix-flatpak;
+            nixpkgs = nixpkgs-stable;
+          };

That looks weird. You barely ever should access the uninstantiated nixpkgs input within the configuration. And nixpkgs.config is not even a thing if nixpkgs is the input.

If though nixpkgs.config refers to an option, your specialArgs don’t do anything for or against it.and if it is the option, then regardless of what input you use, the option is and remains to be nixpkgs.config

1 Like

Ahh then it’s probably the latter your say:

  # Allow unfree packages
  nixpkgs.config.allowUnfree = true;
  # ENABLE LIX-UNSTABLE
  # https://lix.systems/add-to-config/
  # Use latest for unstable (matches our nixos-unstable branch well)
  # Replaces some core programs with lix-built ones
  nixpkgs.overlays = [
    (final: prev: {
      inherit (prev.lixPackageSets.latest)
        nixpkgs-review
        nix-eval-jobs
        nix-fast-build
        colmena
        ;
    })
  ];
  # Replaces system language with lix instead of nix
  nix.package = pkgs.lixPackageSets.latest.lix;

Cool then:)