Using flake-parts, how to refer to `self.packages` from `flake.nixosModules`?

I have a flake that looks roughly like this:

{
  inputs = {
    nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
    flake-parts.url = "github:hercules-ci/flake-parts";
    rust-overlay.url = "github:oxalica/rust-overlay";
  };

  outputs =
    inputs:
    inputs.flake-parts.lib.mkFlake { inherit inputs; } {
      systems = [ "x86_64-linux" ];
      perSystem =
        {
          config,
          self',
          pkgs,
          lib,
          system,
          ...
        }:
        let
          # snip
        in
        {
          formatter = pkgs.nixfmt-tree;
          _module.args.pkgs = import inputs.nixpkgs {
            inherit system;
            overlays = [ (import inputs.rust-overlay) ];
          };

          packages.default = self'.packages.radd;

          packages.radd = (rustPackage "");
        };

      flake.nixosModules.default =
        {
          config,
          self,
          lib,
          pkgs,
          ...
        }:
        let
          cfg = config.services.radd;
          types = lib.types;
        in
        {
          options.services.radd = {
            enable = lib.mkEnableOption "Enable the RuuviTag Additions service.";

            package = lib.mkOption {
              type = types.package;
              default = self.packages.${pkgs.system}.radd;
              description = "The radd package to use.";
            };

          config = lib.mkIf cfg.enable {
            systemd.services.radd = {
              description = "The RuuviTag Additions service.";
              wantedBy = [ "multi-user.target" ];

              serviceConfig = {
                ExecStart = ''
                  bash -c '
                    ${cfg.package}/bin/radd
                  '
                '';
                Restart = "on-failure";
                Type = "exec";
              };
            };
          };
        };
    };
}

When enabling this flake in my nixos config, and running nixos-rebuild, it tells me that self.packages odes not exist in the declaration of the package option of the NixOS module.

Ultimately, I want to refer to packages.${system}.default in the ExecStart of the systemd service. How do I do this?

1 Like

Or, if the above is somehow impossible. What I am trying to do is to create a flake around my rust application that provides it as a systemd service to NixOS. Compiling and running the rust application through nix run works. But I can’t figure out how to get the systemd service to work, because apparently I cannot refer to the nix package of my application from the nixosModule of the same flake.

I guess I could make two flakes, one with the rust package, and one that provides the nixosModule? Is this how people usually do this?

The issue here is that self refers to the NixOS module args, not the f-p args. Removing it should fix the issue.

Edit: The reason this fails, is that your f-p args aren’t guaranteed to be in module args of NixOS (unless you make sure to add them using specialArgs or some other mechanism). By omitting self there, Nix will use the self of f-p during eval, as it’s available in this context.

       flake.nixosModules.default =
         {
           config,
-          self,
           lib,
           pkgs,
           ...
         }:
         let
           cfg = config.services.radd;
1 Like

Thank you so much for the response!

Before removing self as you described, I get this error:

$ nixos-rebuild build                                                                                                                                              1644ms  Wed 05 Nov 2025 06:14:47 PM EET
building the system configuration...
error:
       … while calling the 'head' builtin
         at /nix/store/1wnxdqr2n1pj80lirh9pzsymslx8zd9l-source/lib/attrsets.nix:1696:13:
         1695|           if length values == 1 || pred here (elemAt values 1) (head values) then
         1696|             head values
             |             ^
         1697|           else

       … while evaluating the attribute 'value'
         at /nix/store/1wnxdqr2n1pj80lirh9pzsymslx8zd9l-source/lib/modules.nix:1118:7:
         1117|     // {
         1118|       value = addErrorContext "while evaluating the option `${showOption loc}':" value;
             |       ^
         1119|       inherit (res.defsFinal') highestPrio;

       … while evaluating the option `system.build.toplevel':

       … while evaluating definitions from `/nix/store/1wnxdqr2n1pj80lirh9pzsymslx8zd9l-source/nixos/modules/system/activation/top-level.nix':

       … while evaluating the option `warnings':

       … while evaluating definitions from `/nix/store/1wnxdqr2n1pj80lirh9pzsymslx8zd9l-source/nixos/modules/system/boot/systemd.nix':

       … while evaluating the option `systemd.services.radd.serviceConfig':

       … while evaluating definitions from `/nix/store/xkzr2dfl1yj2qfhjmfv8xbx6hsz4wvcv-source/flake.nix, via option flake.nixosModules.default':

       … while evaluating the option `services.radd.package':

       (stack trace truncated; use '--show-trace' to show the full, detailed trace)

       error: attribute 'packages' missing
       at /nix/store/xkzr2dfl1yj2qfhjmfv8xbx6hsz4wvcv-source/flake.nix:95:25:
           94|               type = types.package;
           95|               default = self.packages.${pkgs.system}.radd;
             |                         ^
           96|               description = "The radd package to use.";
Command 'nix --extra-experimental-features 'nix-command flakes' build --print-out-paths '/etc/nixos#nixosConfigurations."local".config.system.build.toplevel'' returned non-zero exit status 1.

After the change, I cannot even update to the new version of the flake:

$ nix flake update radd                                                                                                                                            1.3m  Wed 05 Nov 2025 06:16:26 PM EET
error:
       … while updating the lock file of flake 'git+file:///etc/nixos?ref=refs/heads/main&rev=37687e9f116e57c1beccfcdb4a4c9707bdd02423'

       … while updating the flake input 'radd'

       error: undefined variable 'self'
       at «github:ISibboI/radd/cdd16a7f7b67dd0fc11672a8eca93785604bc096»/flake.nix:94:25:
           93|               type = types.package;
           94|               default = self.packages.${pkgs.system}.radd;
             |                         ^
           95|               description = "The radd package to use.";

In your case it should be inputs.self because the first line of your outputs function is inputs:.

1 Like

Also if your interested, flake parts has a standard method of accessing self' or inputs' while writing modules using a function called moduleWithSystem: Module Arguments - flake-parts. Using this would allow you to just reference self'.packages.radd instead of self.packages.${pkgs.system}.radd.

1 Like

Thank you so much, this worked!

I think I need a break before I refine my flake any further. But I will consider the moduleWithSystem function in the future, it seems convenient.

And also need something like this for self to be able to be easily accessed by flake = { }; block:

@@ -1,4 +1,4 @@
   outputs =
-    inputs:
+    inputs@{ self, ... }:
     inputs.flake-parts.lib.mkFlake { inherit inputs; } {
       systems = [ "x86_64-linux" ];

Then no need to replace self with inputs.self inside the flake = { }; block.

1 Like

This is kind of a bad pattern that flakes almost encourage: creating an entirely new nixpkgs instance for one package.

Instead, expose an overlay, and consume that overlay in your module. Then pkgs.radd would just work.

2 Likes

I am pretty much a beginner in nix, but if you could point me to an example of a Rust application that is packaged in the way you proposed, I’d be happy to try and copy what they did.