Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 52 additions & 10 deletions docs/content/getting-started/folder_structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -324,26 +324,68 @@ Because the username is part of the path to the configuration, the `home.usernam

## **lib/** for Nix functions.

### `lib/default.nix`
All `.nix` files in `lib/` are automatically imported and exposed as `lib.<name>`.

Loaded if it exists.
### Structure

Inputs:
```
lib/
├── default.nix # Optional: merged into lib
├── strings.nix # Available as lib.strings
└── math.nix # Available as lib.math
```

* `flake`
* `inputs`
### Examples

Flake outputs:
```nix
# lib/add.nix - Simple function
a: b: a + b

# lib/greet.nix - Function with inputs
{ inputs, flake, ... }:
name: "Hello, ${name}!"

# lib/strings.nix - Attrset of functions
{ inputs, flake, ... }:
{
capitalize = str: /* ... */;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what happens if you want to access lib.greet from this file?

kebabToCamel = str: /* ... */;
}
```

### Usage

```nix
inputs.myflake.lib.add 1 2 # => 3
inputs.myflake.lib.greet "World" # => "Hello, World!"
inputs.myflake.lib.strings.capitalize "hello" # => "Hello"
```

Files can optionally receive `{ inputs, flake, ... }` - blueprint auto-detects this.

* `lib` - contains the return value of `lib/default.nix`
`lib/default.nix` exports are merged and take precedence over auto-imported files.

Eg:
### Testing

Export a `tests` attribute from your `lib/` to run [nix-unit](https://github.com/nix-community/nix-unit) tests:

```nix
{ flake, inputs }:
{ }
# lib/default.nix
{ inputs, flake, ... }:
{
add = a: b: a + b;

tests = {
testAdd = {
expr = (import ./default.nix { inherit inputs flake; }).add 1 2;
expected = 3;
};
};
}
```

Tests run automatically with `nix flake check` as `checks.<system>.lib-tests`.

## **`modules/`** for NixOS and other modules.

### `modules/<type>/(<name>|<name>.nix)`
Expand Down
45 changes: 44 additions & 1 deletion lib/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -538,7 +538,50 @@ let
perSystem.self.formatter or pkgs.nixfmt-tree
);

lib = tryImport (src + "/lib") specialArgs;
lib =
let
# Try to load lib/default.nix (legacy behavior)
defaultLib = tryImport (src + "/lib") specialArgs;

# Smart import: check if function expects specialArgs
smartImport = path:
let
module = import path;
in
if builtins.isFunction module then
let
# Get the function's expected arguments
args = builtins.functionArgs module;
# Check if it expects any of the specialArgs keys or has ...
expectsSpecialArgs =
(builtins.length (builtins.attrNames args) > 0) ||
(args ? inputs) ||
(args ? flake) ||
(args ? self);
in
if expectsSpecialArgs then
# Call with specialArgs
module specialArgs
else
# Return function as-is (doesn't expect specialArgs)
module
else
# Not a function, return as-is
module;

# Auto-import lib/* files as an attrset
libFiles = optionalPathAttrs (src + "/lib") (
path:
let
entries = importDir path lib.id;
# Filter out default.nix to avoid duplication
nonDefaultEntries = builtins.removeAttrs entries [ "default" ];
in
lib.mapAttrs (_name: { path, ... }: smartImport path) nonDefaultEntries
);
in
# Merge: lib/default.nix takes precedence, then add auto-imported files
libFiles // defaultLib;

# expose the functor to the top-level
# FIXME: only if it exists
Expand Down