The Nix module system does not resolve dependencies. There is no mechanism by which a module says “I need module B” and B is located and loaded on its behalf. A module that reads config.programs.git.enable when git.nix was never imported does not trigger a fetch; it fails with attribute 'foo' missing, because the option was never declared. Import is the only edge in the graph, and nothing traverses it for you. The system is a flat set-union of whatever you imported, merged to a fixed point.

Two mechanisms are mistaken for dependency management. First, imports is transitive and deduplicated by file path: a module can list its own prerequisites, and the same file reached through many paths collapses to one evaluation (verified: needsLeaf.nix twice plus leaf.nix directly merges once, no double-declaration error; inline function modules do not dedup, since functions are not comparable). That is a module declaring a dependency by importing it, not the system resolving one. Second, an option default referencing another option is a data dependency between values, load-bearing only if the declaring module was already imported.

The consequence is architectural. Because nothing auto-loads, something must enumerate every file for imports: hand-listing, per-module bucket imports (the dendritic answer), or globbing the directory (import-tree, listFilesRecursive). And a genuine cross-module requirement, like a module that dereferences a uvLib arg only present when local.python.enable is true, has no native satisfaction. The only tool the system offers for “A requires B” is assertions: a check that fails, never one that resolves. Nix replaces dependency resolution with explicit composition plus idempotent merge. See Dendritic Pattern Borrows AOP Vocabulary But Realizes SPL Composition and Nix Module System Realizes Multi-Dimensional Separation of Concerns.