1{
2pkgs,
3... # other inputs
4}: {
5# This Nix expression demonstrates how to compose configurations from multiple files.
6# It simulates a modular approach to managing NixOS or home-manager configurations.
7
8# Assume we have several configuration modules in the same directory:
9# - base.nix: Defines common settings, packages, and services.
10# - desktop.nix: Adds desktop-specific packages and settings.
11# - server.nix: Adds server-specific packages and services.
12# - user.nix: Defines user-specific settings and home-manager modules.
13
14# For this example, we'll define these modules inline as strings, but in a real
15# scenario, they would be separate `.nix` files.
16
17# --- Module Definitions (simulated as strings) ---
18baseConfig = pkgs.lib.trivial.importJSON ''
19{
20"description": "Base system configuration",
21"packages": [
22"git",
23"vim",
24"wget"
25],
26"services": {
27"openssh": {
28"enable": true
29}
30},
31"users": {
32"default": {
33"isNormalUser": true,
34"extraGroups": ["wheel"]
35}
36}
37}
38'';
39
40desktopConfig = pkgs.lib.trivial.importJSON ''
41{
42"description": "Desktop environment configuration",
43"packages": [
44"firefox",
45"thunderbird",
46"gnome.gnome-tweaks"
47],
48"services": {
49"displayManager": {
50"enable": true,
51"session": "gnome"
52}
53}
54}
55'';
56
57serverConfig = pkgs.lib.trivial.importJSON ''
58{
59"description": "Server configuration",
60"packages": [
61"nginx",
62"docker"
63],
64"services": {
65"nginx": {
66"enable": true,
67"virtualHosts": {
68"example.com": {
69"root": "/var/www/example.com"
70}
71}
72},
73"docker": {
74"enable": true
75}
76}
77}
78'';
79
80# --- Composition Logic ---
81# We'll use `pkgs.lib.recursiveUpdate` or `pkgs.lib.merge` to combine these.
82# `recursiveUpdate` is often preferred for merging nested attribute sets.
83
84# Start with the base configuration.
85composedConfig = pkgs.lib.recursiveUpdate baseConfig {
86# Merge in desktop configuration.
87# If there are conflicting package lists, the second one (desktopConfig)
88# will overwrite or merge depending on the merge strategy.
89# For lists, `recursiveUpdate` typically concatenates or replaces.
90# For attribute sets, it merges recursively.
91desktopConfig
92};
93
94# Then merge in server configuration.
95composedConfig = pkgs.lib.recursiveUpdate composedConfig {
96serverConfig
97};
98
99# For user-specific settings (e.g., home-manager), the structure might differ.
100# If this were a NixOS configuration, we'd use `imports` in `configuration.nix`.
101# Example: `imports = [ ./base.nix ./desktop.nix ./server.nix ];`
102# The `pkgs.lib.recursiveUpdate` approach here simulates merging attribute sets.
103
104# Let's refine the merging to be more explicit about package lists.
105# A common pattern is to merge package lists by concatenation.
106finalConfig = {
107description = "Composed system configuration";
108
109# Merge packages by concatenating lists.
110packages = pkgs.lib.concatLists [
111baseConfig.packages or []
112desktopConfig.packages or []
113serverConfig.packages or []
114];
115
116# Merge services recursively.
117services = pkgs.lib.recursiveUpdate
118(pkgs.lib.recursiveUpdate
119(baseConfig.services or {})
120(desktopConfig.services or {})
121)
122(serverConfig.services or {});
123
124# Merge users recursively.
125users = pkgs.lib.recursiveUpdate
126(pkgs.lib.recursiveUpdate
127(baseConfig.users or {})
128(desktopConfig.users or {})
129)
130(serverConfig.users or {});
131
132# Add other configuration sections as needed, using appropriate merge strategies.
133};
134
135# The `import` keyword is used to load external `.nix` files.
136# Example: `imports = [ ./my-module.nix ];` in a NixOS `configuration.nix`.
137# This example uses `pkgs.lib.trivial.importJSON` for simplicity, as it doesn't
138# require actual files. In practice, you'd use `import ./path/to/file.nix`.
139
140# The `pkgs.lib.merge` function is another option for combining attribute sets,
141# offering different merge strategies.
142
143# The key takeaway is modularity: break down your configuration into smaller,
144# manageable, and reusable modules, then compose them using Nix's powerful
145# attribute set manipulation functions.
146
147return {
148inherit finalConfig;
149};
150}