Creating a New nix-devshell Module
Checklist
- Create
modules/<name>.nix - Export it in
flake.nixunderflake.flakeModules - If adding a team module, place it in
modules/teams/<name>.nix
Module Template
Needs mattware (Go versions, Zig tools, etc.)
{ mattware }: { lib, ... }: {
perSystem =
{ system, pkgs, config, ... }:
{
options = {
nix-devshell.<name>.package = lib.mkOption {
type = lib.types.package;
default = mattware.packages.${system}.<package>;
defaultText = lib.literalExpression "mattware.packages.\${system}.<package>";
};
};
config = {
devShells.<name> = pkgs.mkShell {
packages = [
config.nix-devshell.<name>.package
pkgs.<tool1>
pkgs.<tool2>
];
};
};
};
}
Only needs nixpkgs (no mattware)
{ lib, ... }: {
perSystem =
{ pkgs, config, ... }:
{
devShells.<name> = pkgs.mkShell {
packages = with pkgs; [ <tool1> <tool2> ];
};
};
}
Team module (wraps base + adds team tools)
{ baseModule }: { ... }: {
imports = [ baseModule ];
perSystem =
{ pkgs, config, ... }:
{
devShells.<teamName> = pkgs.mkShell {
inputsFrom = [ config.devShells.base ];
packages = with pkgs; [ just <team-tools> ];
};
};
}
Exporting in flake.nix
In the flake.flakeModules attrset:
# No nix-devshell inputs needed — direct path
<name> = ./modules/<name>.nix;
# Needs mattware — use importApply
<name> = importApply ./modules/<name>.nix withMattware;
# Team module needing baseModule
<teamName> = importApply ./modules/teams/<teamName>.nix {
baseModule = ./modules/base.nix;
};
withMattware is already defined in flake.nix as { inherit (inputs) mattware; }.
Key Rules
- Use
importApplywhenever the module needs anything from this flake's inputs (mattware). Without it,inputsinside the module refers to the consumer's inputs — mattware won't be there. - Options go under
nix-devshell.<name>.*namespace. - Include
defaultTexton anylib.mkOptionthat uses${system}interpolation (for documentation). - Do not set
systemsin language modules — onlybasesets systems (vialib.mkDefault). - Team modules should use
inputsFrom = [ config.devShells.base ]rather than re-importing base directly, to avoid double-import issues.