nix-config-framework is a small flake-parts framework for convention-based
NixOS, Home Manager, and nix-darwin configurations. It discovers reusable
features from paths and leaves each target's default.nix as the single place
that selects features.
Start with the complete minimal consumer, then use the reference below. Read compatibility and upgrades before changing inputs. For one small home profile, ordinary module imports may be all you need.
Add the framework to a flake and make its core inputs follow your pins:
inputs.nix-config-framework.url = "github:nix-forge/nix-config-framework/v0.1.0";
inputs.nix-config-framework.inputs.nixpkgs.follows = "nixpkgs";
inputs.nix-config-framework.inputs.flake-parts.follows = "flake-parts";
inputs.nix-config-framework.inputs.home-manager.follows = "home-manager";
inputs.nix-config-framework.inputs.nix-darwin.follows = "nix-darwin";
# inside flake-parts mkFlake
imports = [ inputs.nix-config-framework.flakeModules.default ];
nixConfigFramework.root = ./.;
# Optional project-specific helpers for discovered modules:
# nixConfigFramework.extraSpecialArgs.myLib = myLib;When using a git submodule, add self.submodules = true; to the root flake so
the module source is available to Nix.
modules/{nixos,home,darwin,shared}/
hosts/{nixos,darwin}/<host>/{default.nix,local/}
homes/<profile>/{default.nix,local/}
modules/nixos/hardware/sound/pipewire.nix is selectable as
hardware-sound-pipewire. Selecting hardware-sound imports every Nix file
below that directory when it has no default.nix. A directory with a
default.nix is a deliberate feature boundary: selecting it imports that
default module, while its children remain independently selectable variants.
modules/shared/foo.nix returns an envelope with any combination of nixos,
homeManager, and darwin modules. Only the matching class is exported.
Every file beneath a target's local/ directory is imported automatically after
its selected generic features. Keep helpers and inactive experiments outside
local/ (for example under archive/).
# homes/work/default.nix
{ modules, ... }: {
system = "x86_64-linux";
username = "alice";
homeDirectory = "/home/alice";
modules = with modules; [ shells-zsh dev-git ];
}
# hosts/nixos/laptop/default.nix
{ modules, ... }: {
system = "x86_64-linux";
hostName = "laptop";
modules = with modules; [ base ];
homes.alice = {
config = "alice@work";
user = { isNormalUser = true; extraGroups = [ "wheel" ]; };
};
}For a nix-darwin host, set a login shell in the attached user's user attribute
set. The framework registers every such shell in environment.shells, which
causes nix-darwin to manage /etc/shells with the same login-shell path.
homes.alice = {
config = "alice@work";
user.shell = pkgs.nushell;
};Home targets are exported as standalone homeConfigurations by default. Set
standalone = false on a home target when it is intended to run only through
an attached NixOS or nix-darwin host. This is appropriate for profiles that
depend on host-managed services or privileged volatile secret storage.
The flake exports typed flake.modules.{nixos,homeManager,darwin} and the
compatibility aliases nixosModules, homeModules, and darwinModules, as
well as nixosConfigurations, darwinConfigurations, and homeConfigurations.
config.nixConfigFramework.inventory is available to other flake-parts modules
in the same flake for extensions such as secret indexing.
The default system set is x86_64-linux, aarch64-linux, and aarch64-darwin.
Intel macOS consumers should pin a nixpkgs release that still supports
x86_64-darwin and override the flake-parts systems option explicitly.
nix flake check runs the named discovery contracts and integration fixture.
The discovery check forces the fixture's module assertions as well as checking
selected outputs. A failed target-name assertion therefore fails evaluation
without building a Darwin system on Linux.