zenix #
A Standard Opinionated Nix Project Structure inspired by
numtide/blueprint.
Usage #
Add zenix to your flake.nix and pass the entire inputs set to mkFlake:
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
zenix.url = "git+https://tangled.org/jeffydc.xyz/zenix?shallow=1";
};
outputs = inputs: inputs.zenix.lib.mkFlake {
inherit inputs;
systems = [ "x86_64-linux" ];
# Optional: customize the nixpkgs import used for each system.
mkPkgs = system: import inputs.nixpkgs {
inherit system;
config.allowUnfree = true;
};
};
}
By default, zenix reads files under nix/ relative to your flake. For example:
nix/
├── apps/hello.nix → apps.<system>.hello
├── checks/custom.nix → checks.<system>.custom
├── devshells/default.nix → devShells.<system>.default
├── formatter.nix → formatter.<system>
├── hosts/workstation/configuration.nix → nixosConfigurations.workstation
├── modules/core/nixos-module.nix → nixosModules.core
├── modules/core/darwin-module.nix → darwinModules.core
├── modules/network/firewall/nixos-module.nix → nixosModules.network-firewall
├── overlays/default.nix → overlays.default
├── packages/hello.nix → packages.<system>.hello
└── templates/simple/flake.nix → templates.simple
Nested host directories are joined by hyphens: for example,
nix/hosts/region/box/configuration.nix becomes
nixosConfigurations.region-box (and receives hostname = "region-box"). Host
configuration files must be inside a named directory.
For nix-darwin, add a nix-darwin flake input and put host files at
nix/hosts/<name>/darwin-configuration.nix. Each module directory may contain
nixos-module.nix, darwin-module.nix, or both; each file is exported only to
its corresponding output. Module entry points must be inside a named directory.
Shared logic can live outside nix/modules/ and be imported by both entry
points.
Package-style files (apps, checks, devshells, packages, and
formatter.nix) are functions taking zenix arguments first, followed by
arguments supplied through pkgs.callPackage. For example,
nix/packages/hello.nix can contain:
{ inputs, flake }:
{ pkgs, ... }:
pkgs.hello
Here inputs is the flake input set and flake is inputs.self. Host and
module files take the same zenix arguments before the NixOS or nix-darwin module
function; hosts also receive hostname. Overlay files take zenix arguments
before their final: prev: function. Templates are directories, not Nix
functions.
Nested module and overlay paths become names joined by hyphens: for example,
modules/network/firewall/nixos-module.nix becomes
nixosModules.network-firewall. Avoid collisions such as module directories
a/b/ and a-b/, or overlay files a/b.nix and a-b.nix. checks also
includes dev shells, packages, and host system closures prefixed with
devshell-, package-, nixos-, and darwin- respectively. Check names must
be unique; for example, checks/package-hello.nix conflicts with
packages/hello.nix.
mkPkgs receives a system name and returns a nixpkgs package set. Omit it to
use the default import inputs.nixpkgs { inherit system; }. You can also set
root to a different relative directory or a path, and pass systems to choose
target platforms. Run nix flake show to inspect the generated outputs.
Development Guide #
-
Use
snake_casefor internal codes. -
Hard limit comment length at 80 columns.
-
Always run
make fmtandmake ciafter the final changes.