Skip to content

API Reference

As a flake input:

inputs.import-tree
inputs.import-tree.url = "github:vic/import-tree";

As a plain import:

let import-tree = import ./path-to/import-tree;

The resulting value is a callable attrset — the primary import-tree object.


Takes a path or a (nested) list of paths. Returns a Nix module with imports set to all discovered files.

import-tree ./modules
import-tree [ ./modules ./extra ]
import-tree [ ./a [ ./b ] ] # nested lists are flattened

Other import-tree objects can appear in the list as if they were paths.

Anything with an outPath attribute (like flake inputs) is treated as a path:

import-tree [ { outPath = ./modules; } ]

Non-path values (like attrsets) are passed through the filter and included if they pass.


fn : string -> bool — only include paths where fn returns true.

import-tree.filter (lib.hasInfix ".mod.") ./modules

Multiple .filter calls compose with AND.

Inverse of .filter — exclude paths where fn returns true.

import-tree.filterNot (lib.hasInfix "experimental") ./modules

Include only paths matching the regex. Uses builtins.match (tests full string).

import-tree.match ".*/[a-z]+_[a-z]+\.nix" ./modules

Multiple .match calls compose with AND.

Exclude paths matching the regex.

import-tree.matchNot ".*/test_.*\.nix" ./modules

Replaces the default filter (.nix suffix, no /_ infix). Use for non-Nix files or custom ignore conventions.

import-tree.initFilter (lib.hasSuffix ".md") ./docs
import-tree.initFilter (p: lib.hasSuffix ".nix" p && !lib.hasInfix "/skip/" p)

Also applies to non-path items in import lists.


fn : path -> a — transform each discovered path.

import-tree.map lib.traceVal ./modules # trace each path
import-tree.map (p: { imports = [ p ]; }) # wrap in module
import-tree.map import # actually import

Multiple .map calls compose (first map runs first).


Prepend a path to the internal path list. Can be called multiple times:

(import-tree.addPath ./vendor).addPath ./modules
# discovers files in both directories

Extend the import-tree object with new methods. Each value is a function receiving self (the current import-tree):

import-tree.addAPI {
maximal = self: self.addPath ./all-modules;
feature = self: name: self.filter (lib.hasInfix name);
}

Methods are late-bound — you can reference methods added in later .addAPI calls.


Required before .leafs or .pipeTo when used outside module evaluation. Provides lib.filesystem.listFilesRecursive.

import-tree.withLib pkgs.lib

Returns a configured import-tree that produces file lists instead of modules:

(import-tree.withLib lib).leafs ./modules
# => [ ./modules/a.nix ./modules/b.nix ]

Shorthand for .leafs.result:

(import-tree.addPath ./modules).withLib lib |>.files

Like .leafs but pipes the result list through fn:

(import-tree.withLib lib).pipeTo builtins.length ./modules
# => 3

Evaluate with an empty path list. Equivalent to calling with []:

(import-tree.addPath ./modules).result

Returns a fresh import-tree with empty state — no paths, filters, maps, or API extensions.

configured-tree.new # back to a clean slate
Contribute Community Sponsor