Declarative Dependency Injection

2025-05-06

Injecting Dependencies into Modules from a Flake

# flake.nix
let
  # list deps you want passed here
  depInject = { pkgs, lib, ... }: {
    options.dep-inject = lib.mkOption {
      # dep-inject is an attr set of unspecified values
      type = with lib.types; attrsOf unspecified;
      default = { };
    };
    config.dep-inject = {
      # inputs comes from the outer environment of flake.nix
      # usually contains flake inputs, user-defined vars
      # sys metadata
      flake-inputs = inputs;
      userVars = userVars;
      system = system;
      host = host;
      username = username;
    };
  };
in {
  nixosModules.default = { pkgs, lib, ... }: {
    imports = [ depInject ];
  };
}

Example use:

{
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
    home-manager.url = "github:nix-community/home-manager/master";
    home-manager.inputs.nixpkgs.follows = "nixpkgs";
    stylix.url = "github:danth/stylix";
    treefmt-nix.url = "github:numtide/treefmt-nix";
  };

  outputs = { self, nixpkgs, home-manager, stylix, treefmt-nix, ... } @ inputs: let
    system = "x86_64-linux";
    host = "magic";
    username = "jr";
    userVars = {
      timezone = "America/New_York";
      gitUsername = "TSawyer87";
      locale = "en_US.UTF-8";
      dotfilesDir = "~/.dotfiles";
      wm = "hyprland";
      browser = "firefox";
      term = "ghostty";
      editor = "hx";
      keyboardLayout = "us";
    };
    pkgs = import nixpkgs {
      inherit system;
      config.allowUnfree = true;
    };
    treefmtEval = treefmt-nix.lib.evalModule pkgs ./treefmt.nix;

    # Define dep-inject module
    depInject = { pkgs, lib, ... }: {
      options.dep-inject = lib.mkOption {
        type = with lib.types; attrsOf unspecified;
        default = { };
      };
      config.dep-inject = {
        flake-inputs = inputs;
        userVars = userVars; # Add userVars for convenience
        system = system;
        username = username;
        host = host;
      };
    };
  in {
    # Export dep-inject module
    nixosModules.default = { pkgs, lib, ... }: {
          imports = [ depInject ];
    };
    # here we don't need imports = [ depInject { inherit inputs;}]
    # because the vars are captured from the surrounding let block

    # NixOS configuration
    nixosConfigurations = {
      ${host} = nixpkgs.lib.nixosSystem {
        inherit system;
        modules = [
          # enable dep-inject
          self.nixosModules.default
          ./hosts/${host}/configuration.nix
          home-manager.nixosModules.home-manager
          stylix.nixosModules.stylix
          {
            home-manager.useGlobalPkgs = true;
            home-manager.useUserPackages = true;
            home-manager.users.${username} = import ./hosts/${host}/home.nix;
            home-manager.backupFileExtension = "backup";
            # Still need extraSpecialArgs for Home Manager (see below)
            home-manager.extraSpecialArgs = {
              inherit username system host userVars;
            };
          }
        ];
      };
    };

    # Other outputs
    checks.x86_64-linux.style = treefmtEval.config.build.check self;
    formatter.x86_64-linux = treefmtEval.config.build.wrapper;
    devShells.${system}.default = import ./lib/dev-shell.nix { inherit inputs; };
  };
}

Use dep-inject in any Module

Example: System Configuration Module

# configuration.nix
{ config, pkgs, ... }: {
  environment.systemPackages = with config.dep-inject.flake-inputs.nixpkgs.legacyPackages.${pkgs.system}; [
    firefox
    config.dep-inject.userVars.editor # e.g., helix
  ];
  time.timeZone = config.dep-inject.userVars.timezone;
  system.stateVersion = "24.05";
}

Use dep-inject in home-manager modules

  1. Using extraSpecialArgs
home-manager.extraSpecialArgs = {
  inherit username system host userVars;
  depInject = config.dep-inject; # Pass dep-inject
};

Then in ./hosts/${host}/home.nix:

# home.nix
{ depInject, ... }: {
  programs.git = {
    enable = true;
    userName = depInject.userVars.gitUsername;
  };
  home.packages = with depInject.flake-inputs.nixpkgs.legacyPackages.x86_64-linux; [ firefox ];
}
  1. Import depInject into home-manager:
# flake.nix
nixosConfigurations = {
  ${host} = nixpkgs.lib.nixosSystem {
    inherit system;
    modules = [
      self.nixosModules.default # dep-inject for NixOS
      ./hosts/${host}/configuration.nix
      home-manager.nixosModules.home-manager
      stylix.nixosModules.stylix
      {
        home-manager.useGlobalPkgs = true;
        home-manager.useUserPackages = true;
        home-manager.backupFileExtension = "backup";
        home-manager.users.${username} = {
          imports = [ self.nixosModules.default ]; # dep-inject for Home Manager
          # Your Home Manager config
          programs.git = {
            enable = true;
            userName = config.dep-inject.userVars.gitUsername;
          };
          # note: depending on your setup you may need to tweak this
          # `legacyPackages.${pkgs.system}` might be needed
          home.packages = with config.dep-inject.flake-inputs.nixpkgs.legacyPackages.x86_64-linux; [ firefox ];
        };
      }
    ];
  };
};