10 |
11 | Denix is a Nix library designed to help you build scalable configurations for [NixOS](https://nixos.org/), [Home Manager](https://github.com/nix-community/home-manager), and [Nix-Darwin](https://github.com/nix-darwin/nix-darwin).
12 |
13 | ## Documentation
14 |
15 | You can find the documentation here: [Denix Documentation](https://yunfachi.github.io/denix/getting_started/introduction)
16 |
17 | ## Key Features
18 |
19 | ### Modular System
20 | Custom modules allow you to define options and related configurations in a flexible way, simplifying the management of your entire system.
21 |
22 | ### Hosts and Rices
23 | * **Hosts**: Unique configurations tailored for each machine.
24 | * **Rices**: Customizations that can be applied to all hosts.
25 |
26 | ### Unified NixOS, Home Manager, and Nix-Darwin Configurations
27 | Write your NixOS, Home Manager, and Nix-Darwin configurations in a single file*, and Denix will automatically handle the separation for you.
28 |
29 | ## Templates
30 |
31 | ### [minimal](./templates/minimal/) (recommended)
32 | Hosts, rices, and initial modules for quick setup:
33 | ```sh
34 | nix flake init -t github:yunfachi/denix#minimal
35 | ```
36 |
37 | ### [minimal-no-rices](./templates/minimal-no-rices/)
38 | Hosts and initial modules without rices:
39 | ```sh
40 | nix flake init -t github:yunfachi/denix#minimal-no-rices
41 | ```
42 |
--------------------------------------------------------------------------------
/docs/.vitepress/config.mts:
--------------------------------------------------------------------------------
1 | import { defineConfig } from "vitepress"
2 |
3 | // https://vitepress.dev/reference/site-config
4 | export default defineConfig({
5 | cleanUrls: true,
6 | lastUpdated: true,
7 | srcDir: './src',
8 | base: '/denix/', // github pages
9 | ignoreDeadLinks: [
10 | '/TODO'
11 | ],
12 | sitemap: {
13 | hostname: 'https://yunfachi.github.io/denix/'
14 | },
15 | head: [
16 | ["link", { rel: "icon", href: "https://raw.githubusercontent.com/yunfachi/denix/master/.github/assets/logo_dark.svg" }],
17 | ],
18 | themeConfig: {
19 | logo: {
20 | light: "https://raw.githubusercontent.com/yunfachi/denix/master/.github/assets/logo_light.svg",
21 | dark: "https://raw.githubusercontent.com/yunfachi/denix/master/.github/assets/logo_dark.svg",
22 | },
23 | // https://vitepress.dev/reference/default-theme-config
24 | socialLinks: [
25 | { icon: "github", link: "https://github.com/yunfachi/denix" }
26 | ],
27 | search: {
28 | provider: "local",
29 | }
30 | },
31 | locales: {
32 | root: themeConfigEnglish(),
33 | ru: themeConfigRussian()
34 | }
35 | })
36 |
37 | function themeConfigEnglish() {return {
38 | label: "English",
39 | lang: "en",
40 | link: "/",
41 | title: "Denix Documentation",
42 | description: "Nix library for creating scalable NixOS, Home Manager, and Nix-Darwin configurations with modules, hosts, and rices",
43 |
44 | themeConfig: {
45 | editLink: {
46 | pattern: "https://github.com/yunfachi/denix/edit/master/docs/src/:path",
47 | text: "Edit this page on Github"
48 | },
49 |
50 | nav: [
51 | { text: "Home", link: "/" },
52 | { text: "Introduction", link: "/getting_started/introduction" }
53 | ],
54 |
55 | sidebar: [
56 | {
57 | text: "Getting Started",
58 | items: [
59 | { text: "Introduction", link: "/getting_started/introduction" },
60 | { text: "Initialization", link: "/getting_started/initialization" },
61 | { text: "First Modules", link: "/getting_started/first_modules" },
62 | { text: "Transfer to Denix", link: "/getting_started/transfer_to_denix" },
63 | ],
64 | },
65 | {
66 | text: "Modules",
67 | items: [
68 | { text: "Introduction to NixOS Modules", link: "/modules/introduction-nixos" },
69 | { text: "Introduction", link: "/modules/introduction" },
70 | { text: "Structure", link: "/modules/structure" },
71 | { text: "Examples", link: "/modules/examples" }
72 | ],
73 | },
74 | {
75 | text: "Options",
76 | items: [
77 | { text: "Introduction", link: "/options/introduction" },
78 | ],
79 | },
80 | {
81 | text: "Hosts",
82 | items: [
83 | { text: "Introduction", link: "/hosts/introduction" },
84 | { text: "Structure", link: "/hosts/structure" },
85 | { text: "Examples", link: "/hosts/examples" }
86 | ],
87 | },
88 | {
89 | text: "Configurations (flakes)",
90 | items: [
91 | { text: "Introduction", link: "/configurations/introduction" },
92 | { text: "Structure", link: "/configurations/structure" }
93 | ],
94 | },
95 | {
96 | text: "Rices",
97 | items: [
98 | { text: "Introduction", link: "/rices/introduction" },
99 | { text: "Structure", link: "/rices/structure" },
100 | { text: "Examples", link: "/rices/examples" }
101 | ],
102 | },
103 | { text: "Common Errors", link: "/troubleshooting" },
104 | { text: "Real Configurations", link: "/real-configurations" },
105 | ],
106 | }
107 | }}
108 |
109 | function themeConfigRussian() {return {
110 | label: "Русский",
111 | lang: "ru",
112 | link: "/ru/",
113 | title: "Denix Документация",
114 | description: "Библиотека Nix для создания масштабируемых конфигураций NixOS, Home Manager и Nix-Darwin с модулями, хостами и райсами",
115 |
116 | themeConfig: {
117 | editLink: {
118 | pattern: "https://github.com/yunfachi/denix/edit/master/docs/src/:path",
119 | text: "Редактировать эту страницу на GitHub"
120 | },
121 |
122 | nav: [
123 | { text: "Главная", link: "/ru/" },
124 | { text: "Вступление", link: "/ru/getting_started/introduction" }
125 | ],
126 |
127 | sidebar: [
128 | {
129 | text: "Начнем",
130 | items: [
131 | { text: "Вступление", link: "/ru/getting_started/introduction" },
132 | { text: "Инициализация", link: "/ru/getting_started/initialization" },
133 | { text: "Первые модули", link: "/ru/getting_started/first_modules" },
134 | { text: "Перенос на Denix", link: "/ru/getting_started/transfer_to_denix" },
135 | ],
136 | },
137 | {
138 | text: "Модули",
139 | items: [
140 | { text: "Вступление в модули NixOS", link: "/ru/modules/introduction-nixos" },
141 | { text: "Вступление", link: "/ru/modules/introduction" },
142 | { text: "Структура", link: "/ru/modules/structure" },
143 | { text: "Примеры", link: "/ru/modules/examples" },
144 | ],
145 | },
146 | {
147 | text: "Опции",
148 | items: [
149 | { text: "Вступление", link: "/ru/options/introduction" },
150 | ],
151 | },
152 | {
153 | text: "Хосты",
154 | items: [
155 | { text: "Вступление", link: "/ru/hosts/introduction" },
156 | { text: "Структура", link: "/ru/hosts/structure" },
157 | { text: "Примеры", link: "/ru/hosts/examples" },
158 | ],
159 | },
160 | {
161 | text: "Конфигурации (флейки)",
162 | items: [
163 | { text: "Вступление", link: "/ru/configurations/introduction" },
164 | { text: "Структура", link: "/ru/configurations/structure" },
165 | ],
166 | },
167 | {
168 | text: "Райсы",
169 | items: [
170 | { text: "Вступление", link: "/ru/rices/introduction" },
171 | { text: "Структура", link: "/ru/rices/structure" },
172 | { text: "Примеры", link: "/ru/rices/examples" },
173 | ],
174 | },
175 | { text: "Распространённые ошибки", link: "/ru/troubleshooting" },
176 | { text: "Реальные конфигурации", link: "/ru/real-configurations" },
177 | ],
178 | }
179 | }}
180 |
--------------------------------------------------------------------------------
/docs/.vitepress/theme/index.ts:
--------------------------------------------------------------------------------
1 | // https://vitepress.dev/guide/custom-theme
2 | import { h } from 'vue'
3 | import type { Theme } from 'vitepress'
4 | import DefaultTheme from 'vitepress/theme'
5 | import './style.css'
6 |
7 | export default {
8 | extends: DefaultTheme,
9 | Layout: () => {
10 | return h(DefaultTheme.Layout, null, {
11 | // https://vitepress.dev/guide/extending-default-theme#layout-slots
12 | })
13 | },
14 | enhanceApp({ app, router, siteData }) {
15 | // ...
16 | }
17 | } satisfies Theme
18 |
--------------------------------------------------------------------------------
/docs/.vitepress/theme/style.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Customize default theme styling by overriding CSS variables:
3 | * https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css
4 | */
5 |
6 | /**
7 | * Colors
8 | *
9 | * Each colors have exact same color scale system with 3 levels of solid
10 | * colors with different brightness, and 1 soft color.
11 | *
12 | * - `XXX-1`: The most solid color used mainly for colored text. It must
13 | * satisfy the contrast ratio against when used on top of `XXX-soft`.
14 | *
15 | * - `XXX-2`: The color used mainly for hover state of the button.
16 | *
17 | * - `XXX-3`: The color for solid background, such as bg color of the button.
18 | * It must satisfy the contrast ratio with pure white (#ffffff) text on
19 | * top of it.
20 | *
21 | * - `XXX-soft`: The color used for subtle background such as custom container
22 | * or badges. It must satisfy the contrast ratio when putting `XXX-1` colors
23 | * on top of it.
24 | *
25 | * The soft color must be semi transparent alpha channel. This is crucial
26 | * because it allows adding multiple "soft" colors on top of each other
27 | * to create a accent, such as when having inline code block inside
28 | * custom containers.
29 | *
30 | * - `default`: The color used purely for subtle indication without any
31 | * special meanings attched to it such as bg color for menu hover state.
32 | *
33 | * - `brand`: Used for primary brand colors, such as link text, button with
34 | * brand theme, etc.
35 | *
36 | * - `tip`: Used to indicate useful information. The default theme uses the
37 | * brand color for this by default.
38 | *
39 | * - `warning`: Used to indicate warning to the users. Used in custom
40 | * container, badges, etc.
41 | *
42 | * - `danger`: Used to show error, or dangerous message to the users. Used
43 | * in custom container, badges, etc.
44 | * -------------------------------------------------------------------------- */
45 |
46 | :root {
47 | --vp-c-default-1: var(--vp-c-gray-1);
48 | --vp-c-default-2: var(--vp-c-gray-2);
49 | --vp-c-default-3: var(--vp-c-gray-3);
50 | --vp-c-default-soft: var(--vp-c-gray-soft);
51 |
52 | --vp-c-tip-1: var(--vp-c-brand-1);
53 | --vp-c-tip-2: var(--vp-c-brand-2);
54 | --vp-c-tip-3: var(--vp-c-brand-3);
55 | --vp-c-tip-soft: var(--vp-c-brand-soft);
56 |
57 | --vp-c-warning-1: var(--vp-c-yellow-1);
58 | --vp-c-warning-2: var(--vp-c-yellow-2);
59 | --vp-c-warning-3: var(--vp-c-yellow-3);
60 | --vp-c-warning-soft: var(--vp-c-yellow-soft);
61 |
62 | --vp-c-danger-1: var(--vp-c-red-1);
63 | --vp-c-danger-2: var(--vp-c-red-2);
64 | --vp-c-danger-3: var(--vp-c-red-3);
65 | --vp-c-danger-soft: var(--vp-c-red-soft);
66 | }
67 |
68 | /**
69 | * Component: Button
70 | * -------------------------------------------------------------------------- */
71 |
72 | :root {
73 | --vp-button-brand-border: transparent;
74 | --vp-button-brand-text: var(--vp-c-white);
75 | --vp-button-brand-bg: var(--vp-c-brand-3);
76 | --vp-button-brand-hover-border: transparent;
77 | --vp-button-brand-hover-text: var(--vp-c-white);
78 | --vp-button-brand-hover-bg: var(--vp-c-brand-2);
79 | --vp-button-brand-active-border: transparent;
80 | --vp-button-brand-active-text: var(--vp-c-white);
81 | --vp-button-brand-active-bg: var(--vp-c-brand-1);
82 | }
83 |
84 | /**
85 | * Component: Home
86 | * -------------------------------------------------------------------------- */
87 |
88 | :root {
89 | --vp-home-hero-name-color: transparent;
90 | --vp-home-hero-name-background: -webkit-linear-gradient(
91 | 120deg,
92 | #95b695 30%,
93 | #6f866f
94 | );
95 |
96 | --vp-home-hero-image-filter: blur(44px);
97 | }
98 |
99 | .dark {
100 | --vp-home-hero-image-background-image: linear-gradient(
101 | -45deg,
102 | #6f866f 50%,
103 | #6f866f 50%
104 | );
105 |
106 | --vp-c-brand-1: #95b695;
107 | --vp-c-brand-2: #869e86;
108 | --vp-c-brand-3: #6f866f;
109 | --vp-c-brand-soft: var(--vp-c-green-soft);
110 | }
111 |
112 | html:not(.dark) {
113 | --vp-home-hero-image-background-image: linear-gradient(
114 | -45deg,
115 | #a7caa7 50%,
116 | #a7caa7 50%
117 | );
118 |
119 | --vp-c-brand-1: #6f866f;
120 | --vp-c-brand-2: #869e86;
121 | --vp-c-brand-3: #95b695;
122 | --vp-c-brand-soft: var(--vp-c-green-soft);
123 | }
124 |
125 | @media (min-width: 640px) {
126 | :root {
127 | --vp-home-hero-image-filter: blur(56px);
128 | }
129 | }
130 |
131 | @media (min-width: 960px) {
132 | :root {
133 | --vp-home-hero-image-filter: blur(68px);
134 | }
135 | }
136 |
137 | /**
138 | * Component: Custom Block
139 | * -------------------------------------------------------------------------- */
140 |
141 | :root {
142 | --vp-custom-block-tip-border: transparent;
143 | --vp-custom-block-tip-text: var(--vp-c-text-1);
144 | --vp-custom-block-tip-bg: var(--vp-c-brand-soft);
145 | --vp-custom-block-tip-code-bg: var(--vp-c-brand-soft);
146 | }
147 |
148 | /**
149 | * Component: Algolia
150 | * -------------------------------------------------------------------------- */
151 |
152 | .DocSearch {
153 | --docsearch-primary-color: var(--vp-c-brand-1) !important;
154 | }
155 |
156 |
--------------------------------------------------------------------------------
/docs/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "devDependencies": {
3 | "vitepress": "^1.6.3"
4 | },
5 | "scripts": {
6 | "docs:dev": "vitepress dev",
7 | "docs:build": "vitepress build",
8 | "docs:preview": "vitepress preview"
9 | }
10 | }
--------------------------------------------------------------------------------
/docs/src/configurations/introduction.md:
--------------------------------------------------------------------------------
1 | # Introduction to Denix Configurations (Flakes) {#introduction}
2 | The `delib.configurations` function is used to create lists of `nixosConfigurations`, `homeConfigurations`, and `darwinConfigurations` for flakes.
3 |
4 | In addition to all hosts, it also adds combinations of each host with every **non-`inheritanceOnly`** rice, which allows for quickly switching between rice configurations without editing the code. For example, if the "desktop" host is set to use the "light" rice, executing the following command:
5 |
6 | ```sh
7 | nixos-rebuild switch --flake .#desktop --use-remote-sudo
8 | ```
9 |
10 | will use the "desktop" host with the "light" rice. However, if you need to quickly switch to another rice, for example, "dark" you can run the following command:
11 |
12 | ```sh
13 | nixos-rebuild switch --flake .#desktop-dark --use-remote-sudo
14 | ```
15 |
16 | In this case, the host remains "desktop", but the rice changes to "dark".
17 |
18 | It is important to note that when switching rice in this way, only the value of the `${myConfigName}.rice` option changes, while the value of `${myConfigName}.hosts.${hostName}.rice` remains the same.
19 |
20 | ## Principle of Configuration List Generation {#principle}
21 | The configuration list is generated based on the following principle:
22 |
23 | - `{hostName}` - where `hostName` is the name of any host.
24 | - `{hostName}-{riceName}` - where `hostName` is the name of any host, and `riceName` is the name of any rice where `inheritanceOnly` is `false`.
25 |
26 | If `moduleSystem` from the [function arguments](/configurations/structure#function-arguments) is set to `home`, then a prefix of `{homeManagerUser}@` is added to all configurations in the list.
27 |
28 | ## Example {#example}
29 | An example of a flake's `outputs` for `nixosConfigurations`, `homeConfigurations`, and `darwinConfigurations`:
30 |
31 | ```nix
32 | outputs = {denix, nixpkgs, ...} @ inputs: let
33 | mkConfigurations = moduleSystem:
34 | denix.lib.configurations rec {
35 | inherit moduleSystem;
36 | homeManagerUser = "sjohn";
37 |
38 | paths = [./hosts ./modules ./rices];
39 |
40 | specialArgs = {
41 | inherit inputs moduleSystem homeManagerUser;
42 | };
43 | };
44 | in {
45 | nixosConfigurations = mkConfigurations "nixos";
46 | homeConfigurations = mkConfigurations "home";
47 | darwinConfigurations = mkConfigurations "darwin";
48 | }
49 | ```
50 |
--------------------------------------------------------------------------------
/docs/src/configurations/structure.md:
--------------------------------------------------------------------------------
1 | # Structure {#structure}
2 |
3 | ## Function Arguments {#function-arguments}
4 | - `myconfigName` (string): the category for all Denix module options, hosts, and rices. Default is `myconfig`; changes are not recommended.
5 | - `denixLibName` (string): the name of the Denix library in `specialArgs` (`{denixLibName, ...}: denixLibName.module { ... }`). Default is `delib`; changes are not recommended.
6 | - `homeManagerNixpkgs` (nixpkgs): used in the `pkgs` attribute of the `home-manager.lib.homeManagerConfiguration` function in the format: `homeManagerNixpkgs.legacyPackages.${host :: homeManagerSystem}`. By default, it takes `nixpkgs` from the flake, so if you've set `inputs.denix.inputs.nixpkgs.follows = "nixpkgs";`, specifying `homeManagerNixpkgs` is typically unnecessary.
7 | - `homeManagerUser` (string): the username, used in `home-manager.users.${homeManagerUser}` and for generating the Home Manager configuration list.
8 | - `moduleSystem` ("nixos", "home", and "darwin"): specifies which module system the configuration list should be generated for - NixOS, Home Manager, or Nix-Darwin.
9 | - `paths` (listOf string): paths to be imported; add hosts, rices, and modules here. Default is `[]`.
10 | - `exclude` (listOf string): paths to be excluded from importing. Default is `[]`.
11 | - `recursive` (boolean): determines whether to recursively search for paths to import. Default is `true`.
12 | - `specialArgs` (attrset): `specialArgs` to be passed to `lib.nixosSystem`, `home-manager.lib.homeManagerConfiguration`, and `nix-darwin.lib.darwinSystem`. Default is `{}`.
13 | - **EXPERIMENTAL** `extraModules` (list): default is `[]`.
14 | - **EXPERIMENTAL** `mkConfigurationsSystemExtraModule` (attrset): a module used in the internal NixOS configuration that receives the list of hosts and rices to generate the configuration list. Default is `{nixpkgs.hostPlatform = "x86_64-linux";}`.
15 |
16 | ## Pseudocode {#pseudocode}
17 | ```nix
18 | delib.configurations {
19 | myconfigName = "myconfig";
20 | denixLibName = "delib";
21 | homeManagerNixpkgs = inputs.nixpkgs;
22 | homeManagerUser = "sjohn";
23 | moduleSystem = "nixos";
24 | paths = [./modules ./hosts ./rices];
25 | exclude = [./modules/deprecated];
26 | recursive = true;
27 | specialArgs = {
28 | inherit inputs;
29 | };
30 | }
31 |
--------------------------------------------------------------------------------
/docs/src/getting_started/first_modules.md:
--------------------------------------------------------------------------------
1 | # First Modules {#first-modules}
2 | In this section, we will create modules for some programs. To start, create the `programs` and `services` subdirectories in the `modules` directory.
3 |
4 | Creating your own modules is almost the same as creating regular NixOS modules, so you can look for NixOS options [here](https://search.nixos.org/options?), Home Manager options [here](https://home-manager-options.extranix.com/), and Nix-Darwin options [here](https://nix-darwin.github.io/nix-darwin/manual/index.html).
5 |
6 | ## Git {#git}
7 | Let's assume you already have a constants module. Create a file `modules/programs/git.nix` with the following content:
8 | ```nix
9 | {delib, ...}:
10 | delib.module {
11 | name = "programs.git";
12 |
13 | options.programs.git = with delib; {
14 | enable = boolOption true;
15 | enableLFS = boolOption true;
16 | };
17 |
18 | home.ifEnabled.programs.git = {myconfig, cfg, ...}: {
19 | enable = cfg.enable;
20 | lfs.enable = cfg.enableLFS;
21 |
22 | userName = myconfig.constants.username;
23 | userEmail = myconfig.constants.useremail;
24 | };
25 | }
26 | ```
27 |
28 | ### Code Explanation:
29 | - `enable` - an option to enable or disable the module entirely.
30 | - `enableLFS` - an option to enable [Git Large File Storage](https://github.com/git-lfs/git-lfs).
31 |
32 | ## Hyprland {#hyprland}
33 | Assume that your host has the options `type` and `isDesktop`. Create a subdirectory `hyprland` in the `modules/programs/` directory, and in it, create a file `default.nix` with the following content:
34 | ```nix
35 | {delib, ...}:
36 | delib.module {
37 | name = "programs.hyprland";
38 |
39 | options = {myconfig, ...} @ args: delib.singleEnableOption myconfig.host.isDesktop args;
40 |
41 | nixos.ifEnabled.programs.hyprland.enable = true;
42 | home.ifEnabled.wayland.windowManager.hyprland.enable = true;
43 | }
44 | ```
45 |
46 | Also, create a file `settings.nix` in this directory:
47 | ```nix
48 | {delib, ...}:
49 | delib.module {
50 | name = "programs.hyprland";
51 |
52 | home.ifEnabled.wayland.windowManager.hyprland.settings = {
53 | "$mod" = "SUPER";
54 |
55 | general = {
56 | gaps_in = 5;
57 | gaps_out = 10;
58 | };
59 | };
60 | }
61 | ```
62 |
63 | And finally, the file `binds.nix`:
64 | ```nix
65 | {delib, ...}:
66 | delib.module {
67 | name = "programs.hyprland";
68 |
69 | home.ifEnabled.wayland.windowManager.hyprland.settings = {
70 | bindm = [
71 | "$mod, mouse:272, movewindow"
72 | "$mod, mouse:273, resizewindow"
73 | ];
74 |
75 | bind = [
76 | "$mod, q, killactive,"
77 | "CTRLALT, Delete, exit,"
78 |
79 | "$mod, Return, exec, kitty" # your terminal
80 | ];
81 | };
82 | }
83 | ```
84 |
85 | We have created a small configuration for Hyprland, which you can expand and add new options to as needed.
86 |
--------------------------------------------------------------------------------
/docs/src/getting_started/initialization.md:
--------------------------------------------------------------------------------
1 | # Configuration Initialization {#initialization}
2 | This section will describe creating the `minimal` template from scratch.
3 |
4 | You do not have to do this; you can simply clone the minimal configuration template with the following command:
5 | ```sh
6 | nix flake init -t github:yunfachi/denix#minimal
7 | ```
8 |
9 | You can also clone the minimal configuration template without the rices:
10 | ```sh
11 | nix flake init -t github:yunfachi/denix#minimal-no-rices
12 | ```
13 |
14 | ## Flake {#flake}
15 | First, create a directory for your configuration and a `flake.nix` file with the following content:
16 | ```nix
17 | {
18 | description = "Modular configuration of NixOS, Home Manager, and Nix-Darwin with Denix";
19 |
20 | inputs = {
21 | nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
22 | home-manager = {
23 | url = "github:nix-community/home-manager/master";
24 | inputs.nixpkgs.follows = "nixpkgs";
25 | };
26 | denix = {
27 | url = "github:yunfachi/denix";
28 | inputs.nixpkgs.follows = "nixpkgs";
29 | inputs.home-manager.follows = "home-manager";
30 | };
31 | };
32 |
33 | outputs = {
34 | denix,
35 | nixpkgs,
36 | ...
37 | } @ inputs: let
38 | mkConfigurations = moduleSystem:
39 | denix.lib.configurations {
40 | inherit moduleSystem;
41 | homeManagerUser = "sjohn"; #!!! REPLACEME
42 |
43 | paths = [./hosts ./modules ./rices];
44 |
45 | specialArgs = {
46 | inherit inputs;
47 | };
48 | };
49 | in {
50 | # If you're not using NixOS, Home Manager, or Nix-Darwin,
51 | # you can safely remove the corresponding lines below.
52 | nixosConfigurations = mkConfigurations "nixos";
53 | homeConfigurations = mkConfigurations "home";
54 | darwinConfigurations = mkConfigurations "darwin";
55 | };
56 | }
57 | ```
58 |
59 | If you are not familiar with `inputs` and `outputs`, read [NixOS Wiki Flakes](https://nixos.wiki/wiki/Flakes).
60 |
61 | Code explanation:
62 | - `mkConfigurations` - a function to reduce code repetition, which takes `moduleSystem` and passes it to `denix.lib.configurations`.
63 | - `denix.lib.configurations` - [Configurations (flakes) - Introduction](/configurations/introduction).
64 | - `paths = [./hosts ./modules ./rices];` - paths that will be recursively imported by Denix as modules. Remove `./rices` if you don't plan to use rices.
65 |
66 | ## Hosts {#hosts}
67 | Create a `hosts` directory, and within it, create a subdirectory with the name of your host, for example, `desktop`.
68 |
69 | In this subdirectory, create a `default.nix` file with the following content:
70 | ```nix
71 | {delib, ...}:
72 | delib.host {
73 | name = "desktop"; #!!! REPLACEME
74 | }
75 | ```
76 |
77 | In the same directory, create a `hardware.nix` file:
78 | ```nix
79 | {delib, ...}:
80 | delib.host {
81 | name = "desktop"; #!!! REPLACEME
82 |
83 | homeManagerSystem = "x86_64-linux"; #!!! REPLACEME
84 | home.home.stateVersion = "24.05"; #!!! REPLACEME
85 |
86 | # If you're not using NixOS, you can remove this entire block.
87 | nixos = {
88 | nixpkgs.hostPlatform = "x86_64-linux"; #!!! REPLACEME
89 | system.stateVersion = "24.05"; #!!! REPLACEME
90 |
91 | # nixos-generate-config --show-hardware-config
92 | # other generated code here...
93 | };
94 |
95 | # If you're not using Nix-Darwin, you can remove this entire block.
96 | darwin = {
97 | nixpkgs.hostPlatform = "aarch64-darwin"; #!!! REPLACEME
98 | system.stateVersion = 6; #!!! REPLACEME
99 | };
100 | }
101 | ```
102 |
103 | The `default.nix` file will be modified later after adding modules and rices, so you can keep it open.
104 |
105 | ## Rices {#rices}
106 | Skip this section if you do not wish to use rices.
107 |
108 | Create a `rices` directory, and within it, create a subdirectory with the name of your rice, for example, `dark`.
109 |
110 | In this subdirectory, create a `default.nix` file with the following content:
111 | ```nix
112 | {delib, ...}:
113 | delib.rice {
114 | name = "dark"; #!!! REPLACEME
115 | }
116 | ```
117 |
118 | ## Modules {#modules}
119 | Create a `modules` directory, and within it, create a `config` subdirectory (typically, it contains modules that are not tied to a specific program or service).
120 |
121 | It should be mentioned that modules represent your configuration, meaning it's up to your imagination, and you are free to change the modules as you wish.
122 |
123 | ### Constants {#modules-constants}
124 | In this subdirectory, create a `constants.nix` file with the following content:
125 | ```nix
126 | {delib, ...}:
127 | delib.module {
128 | name = "constants";
129 |
130 | options.constants = with delib; {
131 | username = readOnly (strOption "sjohn"); #!!! REPLACEME
132 | userfullname = readOnly (strOption "John Smith"); #!!! REPLACEME
133 | useremail = readOnly (strOption "johnsmith@example.com"); #!!! REPLACEME
134 | };
135 | }
136 | ```
137 |
138 | This file is optional, as are any of its options, which are only used by you, but it is recommended as good practice.
139 |
140 | ### Hosts {#modules-hosts}
141 | Also, create a `hosts.nix` file in this same directory (`modules/config`), and write any example from [Hosts - Examples](/hosts/examples).
142 |
143 | For example, we will take ["With the `type` Option"](/hosts/examples#type-option):
144 | ```nix
145 | {delib, ...}:
146 | delib.module {
147 | name = "hosts";
148 |
149 | options = with delib; let
150 | host = {config, ...}: {
151 | options =
152 | hostSubmoduleOptions
153 | // {
154 | type = noDefault (enumOption ["desktop" "server"] null);
155 |
156 | isDesktop = boolOption (config.type == "desktop");
157 | isServer = boolOption (config.type == "server");
158 | };
159 | };
160 | in {
161 | host = hostOption host;
162 | hosts = hostsOption host;
163 | };
164 |
165 | home.always = {myconfig, ...}: {
166 | assertions = delib.hostNamesAssertions myconfig.hosts;
167 | };
168 | }
169 | ```
170 |
171 | If you added an example with new options (`type`, `displays`, etc.) or made your own options, don't forget to add values for these options in the hosts.
172 |
173 | In our example, we added the `type` option, so open the `default.nix` file in your host's directory and add the attribute `type` to the `delib.host` function:
174 | ```nix
175 | {delib, ...}:
176 | delib.host {
177 | name = "desktop"; #!!! REPLACEME
178 |
179 | type = "desktop" #!!! REPLACEME ["desktop"|"server"]
180 |
181 | # ...
182 | }
183 | ```
184 |
185 | ### Rices {#modules-rices}
186 | Skip this section if you are not using rices.
187 |
188 | In the `modules/config` directory, create a `rices.nix` file, and write any example from [Rices - Examples](/rices/examples).
189 |
190 | For example, we will take ["Minimally Recommended Rice Module"](/rices/examples#minimally-recommended):
191 | ```nix
192 | delib.module {
193 | name = "rices";
194 |
195 | options = with delib; let
196 | rice = {
197 | options = riceSubmoduleOptions;
198 | };
199 | in {
200 | rice = riceOption rice;
201 | rices = ricesOption rice;
202 | };
203 |
204 | home.always = {myconfig, ...}: {
205 | assertions = delib.riceNamesAssertions myconfig.rices;
206 | };
207 | }
208 | ```
209 |
210 | Also, open the `default.nix` file of your host and add the attribute `rice` to the `delib.host` function:
211 | ```nix
212 | {delib, ...}:
213 | delib.host {
214 | name = "desktop"; #!!! REPLACEME
215 |
216 | rice = "dark" #!!! REPLACEME
217 |
218 | # ...
219 | }
220 | ```
221 |
222 | ### Home Manager {#modules-home-manager}
223 | If you created a [constants module](#modules-constants), just create a `home.nix` file with the following content:
224 | ```nix
225 | {delib, pkgs, ...}:
226 | delib.module {
227 | name = "home";
228 |
229 | home.always = {myconfig, ...}: let
230 | inherit (myconfig.constants) username;
231 | in {
232 | home = {
233 | inherit username;
234 | # If you don't need Nix-Darwin, or if you're using it exclusively,
235 | # you can keep the string here instead of the condition.
236 | homeDirectory =
237 | if pkgs.stdenv.isDarwin
238 | then "/Users/${username}"
239 | else "/home/${username}";
240 | };
241 | };
242 | }
243 | ```
244 |
245 | If you did not use the [constants module](#modules-constants), the content of the file will be:
246 | ```nix
247 | {delib, pkgs, ...}:
248 | delib.module {
249 | name = "home";
250 |
251 | home.always.home = {
252 | username = "sjohn"; #!!! REPLACEME
253 | # If you don't need Nix-Darwin, or if you're using it exclusively,
254 | # you can keep the string here instead of the condition.
255 | homeDirectory =
256 | if pkgs.stdenv.isDarwin
257 | then "/Users/sjohn" #!!! REPLACEME
258 | else "/home/sjohn"; #!!! REPLACEME
259 | };
260 | }
261 | ```
262 |
263 | ### User {#modules-user}
264 | You can also create a `user.nix` file with the configuration of your NixOS and Nix-Darwin user:
265 | ```nix
266 | {delib, ...}:
267 | delib.module {
268 | name = "user";
269 |
270 | # If you're not using NixOS, you can remove this entire block.
271 | nixos.always = {myconfig, ...}: let
272 | inherit (myconfig.constants) username;
273 | in {
274 | users = {
275 | groups.${username} = {};
276 |
277 | users.${username} = {
278 | isNormalUser = true;
279 | initialPassword = username;
280 | extraGroups = ["wheel"];
281 | };
282 | };
283 | };
284 |
285 | # If you're not using Nix-Darwin, you can remove this entire block.
286 | darwin.always = {myconfig, ...}: let
287 | inherit (myconfig.constants) username;
288 | in {
289 | users.users.${username} = {
290 | name = username;
291 | home = "/Users/${username}";
292 | };
293 | };
294 | }
295 | ```
296 |
297 | If you did not use the [constants module](#modules-constants), the content of the file will be:
298 | ```nix
299 | {delib, ...}:
300 | delib.module {
301 | name = "user";
302 |
303 | # If you're not using NixOS, you can remove this entire block.
304 | nixos.always.users = {
305 | groups.sjohn = {}; #!!! REPLACEME
306 |
307 | users.sjohn = { #!!! REPLACEME
308 | isNormalUser = true;
309 | initialPassword = "sjohn"; #!!! REPLACEME
310 | extraGroups = ["wheel"];
311 | };
312 | };
313 |
314 | # If you're not using Nix-Darwin, you can remove this entire block.
315 | darwin.always.users.users."sjohn" = { #!!! REPLACEME
316 | name = "sjohn"; #!!! REPLACEME
317 | home = "/Users/sjohn"; #!!! REPLACEME
318 | };
319 | }
320 | ```
321 |
322 | ## Conclusion {#conclusion}
323 | If you have followed the instructions precisely, you will end up with the following configuration directory tree:
324 | ```plaintext
325 | hosts
326 | - desktop
327 | - default.nix
328 | - hardware.nix
329 | modules
330 | - config
331 | - constants.nix
332 | - home.nix
333 | - hosts.nix
334 | - rices.nix
335 | - user.nix
336 | rices
337 | - dark
338 | - default.nix
339 | flake.nix
340 | ```
341 |
342 | You can check if everything is set up correctly using the command:
343 | ```sh
344 | nix flake check .#
345 | ```
346 |
--------------------------------------------------------------------------------
/docs/src/getting_started/introduction.md:
--------------------------------------------------------------------------------
1 | # Introduction {#introduction}
2 | In this section, you will learn about what Denix is, why it is needed, who can benefit from it, and popular practices for system configuration.
3 |
4 | ## What is Denix {#what-is-denix}
5 | Denix is a Nix library designed for creating scalable configurations for [NixOS](https://nixos.org/), [Home Manager](https://github.com/nix-community/home-manager), and [Nix-Darwin](https://github.com/nix-darwin/nix-darwin).
6 |
7 | It provides functions that transform input data into a module according to a specific algorithm. Thanks to this, if for any reason you need to create a module without using Denix, it will be sufficient to import the file with it, and everything will work.
8 |
9 | The provided functions are generally divided into five categories:
10 | - Creating configurations for Flake ([NixOS](https://nixos.org/), [Home Manager](https://github.com/nix-community/home-manager), or [Nix-Darwin](https://github.com/nix-darwin/nix-darwin))
11 | - Options - an analogue of types and functions for creating options from [Nixpkgs](https://github.com/NixOS/nixpkgs)
12 | - [Modules](#modules)
13 | - [Hosts](#hosts)
14 | - [Rices](#rices)
15 |
16 | ## Why and Who Needs Denix {#why-and-who-needs-denix}
17 | Denix is primarily needed to simplify the creation, editing, and readability of configuration code. It eliminates the need to create typical expressions for your own modules, hosts, rices, etc.
18 |
19 | If you plan to expand your configuration across multiple machines (hosts), want to have various system settings (rices) that can be changed with a single command, and strive to write readable and clean code, then you should consider trying Denix. Conversely, if you're creating a small configuration for a single machine and don't plan to expand it, Denix might be unnecessary.
20 |
21 | Configuration templates using Denix can be found in the `templates` directory of the GitHub repository: [github:yunfachi/denix?path=templates](https://github.com/yunfachi/denix/tree/master/templates).
22 |
23 | ## Modules {#modules}
24 | Custom modules are possibly the best practice for creating scalable configurations.
25 |
26 | A module includes options, configuration, and importing other modules.
27 | - `options = {};`: Similar to declaring variables in programming, but here it's a declaration of options.
28 | - `config = {};`: Similar to initializing variables, but here it's about specifying values for options.
29 | - `imports = [];`: A list of paths to modules or just module code (attrset or lambda that returns attrset).
30 |
31 | NixOS, Home Manager, and Nix-Darwin have their own modules, which you have likely already worked with. You can search for options on these sites:
32 | - NixOS: https://search.nixos.org/options
33 | - Home Manager: https://home-manager-options.extranix.com/
34 | - Nix-Darwin: https://nix-darwin.github.io/nix-darwin/manual/
35 |
36 | Example of custom NixOS module code without using Denix:
37 | ```nix
38 | {
39 | lib,
40 | config,
41 | ...
42 | }: {
43 | options = {
44 | example = {
45 | enable = lib.mkEnableOption "example" // {default = true;};
46 | hostnames = lib.mkOption {
47 | type = lib.types.listOf lib.types.str;
48 | default = [];
49 | };
50 | };
51 | };
52 |
53 | config = lib.mkIf (!config.example.enable) {
54 | networking.hosts."127.0.0.1" = config.example.hostnames;
55 | };
56 | }
57 | ```
58 | The same functionality but using Denix:
59 | ```nix
60 | {delib, ...}:
61 | delib.module {
62 | name = "example";
63 |
64 | options.example = with delib; {
65 | enable = enableOption true;
66 | hostnames = listOfOption str [];
67 | };
68 |
69 | nixos.ifEnabled = {cfg, ...}: {
70 | networking.hosts."127.0.0.1" = cfg.hostnames;
71 | };
72 | }
73 | ```
74 | You can learn more about Denix modules in [Modules](/modules/introduction).
75 |
76 | ## Hosts {#hosts}
77 | Host is any machine, such as a personal computer, server, etc.
78 |
79 | The essence of this practice is to separate the configuration into a shared part and a unique part for each host.
80 |
81 | Example of a host configuration module using Denix:
82 | ```nix
83 | {delib, ...}:
84 | delib.host {
85 | name = "macbook";
86 |
87 | rice = "dark";
88 | type = "desktop";
89 |
90 | homeManagerSystem = "x86_64-darwin";
91 | home.home.stateVersion = "24.05";
92 |
93 | shared.myconfig = {
94 | services.openssh.authorizedKeys = ["ssh-ed25519 ..."];
95 | };
96 | }
97 | ```
98 | You can learn more about Denix hosts in [Hosts](/hosts/introduction).
99 |
100 | ## Rices {#rices}
101 | Rice is a slang term used to describe system settings, especially related to appearance.
102 |
103 | In our case, this is any configuration not tied to a specific host.
104 |
105 | Example of a rice configuration module using Denix:
106 | ```nix
107 | {delib, ...}:
108 | delib.rice {
109 | name = "dark";
110 |
111 | home.stylix = {
112 | polarity = "dark";
113 | colors = {
114 | # ...
115 | };
116 | };
117 | }
118 | ```
119 | You can learn more about Denix rices in [Rices](/rices/introduction).
120 |
--------------------------------------------------------------------------------
/docs/src/getting_started/transfer_to_denix.md:
--------------------------------------------------------------------------------
1 | # Transfer to Denix {#transfer-to-denix}
2 | If you already have a NixOS, Home Manager, or Nix-Darwin configuration, you can transfer most of the code without significant changes and then adapt it for Denix.
3 |
4 | However, you will need to create the following from scratch:
5 | - Hosts
6 | - Rices (if you want)
7 | - Some initial modules
8 |
9 | The main part of the configuration can be fully reused from your old setup. The key is to separate the hardware configuration from the general configuration. See the section [How Does It Work?](#how-it-works).
10 |
11 | ## How Does It Work? {#how-it-works}
12 | All Denix modules are standard NixOS, Home Manager, or Nix-Darwin modules but with additional logic for enabling and disabling configurations.
13 |
14 | This means that you can add code or files from the old configuration into the new one, so they are imported through [`delib.configurations`](/configurations/introduction). You can place this code in the `modules` directory or create a new one, for example, `modules_nixos_old` for older configurations.
15 |
16 | ## Example of a Simple Configuration {#example-of-simple-configuration}
17 | Suppose you have an old configuration consisting of two files: `configuration.nix` and `hardware-configuration.nix`, and you've already created hosts and the `modules/config` directory following the instructions. The configuration for your host should include `hardware-configuration.nix`, so all that remains is to copy `configuration.nix` into the `modules` directory and remove unnecessary options, like `system.stateVersion`.
18 |
19 | ## Example of a Complex Configuration {#example-of-complex-configuration}
20 | Suppose you have an old configuration with hosts and multiple modules split across files. Hosts are typically specific to your system, so you will need to transfer them manually, usually by just copying the code.
21 |
22 | Modules (e.g., for programs and services) can simply be copied into the `modules` directory or other files imported via [`delib.configurations`](/configurations/introduction).
23 |
--------------------------------------------------------------------------------
/docs/src/hosts/examples.md:
--------------------------------------------------------------------------------
1 | # Examples {#examples}
2 |
3 | ## Minimally Recommended Host Module: {#minimally-recommended}
4 | An example of a minimal host module configuration that serves as a baseline for all further settings:
5 |
6 | ```nix
7 | {delib, ...}:
8 | delib.module {
9 | name = "hosts";
10 |
11 | options = with delib; let
12 | host = {
13 | options = hostSubmoduleOptions;
14 | };
15 | in {
16 | host = hostOption host;
17 | hosts = hostsOption host;
18 | };
19 |
20 | home.always = {myconfig, ...}: {
21 | assertions = delib.hostNamesAssertions myconfig.hosts;
22 | };
23 | }
24 | ```
25 |
26 | ## With the `type` Option {#type-option}
27 | The `type` option **is very** useful for default values in your modules. For example, the option `enable = boolOption host.isDesktop` can be used for some GUI programs. This simplifies configuration management based on the type of device.
28 |
29 | ```nix
30 | {delib, ...}:
31 | delib.module {
32 | name = "hosts";
33 |
34 | options = with delib; let
35 | host = {config, ...}: {
36 | options =
37 | hostSubmoduleOptions
38 | // {
39 | type = noDefault (enumOption ["desktop" "server"] null);
40 |
41 | isDesktop = boolOption (config.type == "desktop");
42 | isServer = boolOption (config.type == "server");
43 | };
44 | };
45 | in {
46 | host = hostOption host;
47 | hosts = hostsOption host;
48 | };
49 |
50 | home.always = {myconfig, ...}: {
51 | assertions = delib.hostNamesAssertions myconfig.hosts;
52 | };
53 | }
54 | ```
55 |
56 | ## With the `displays` Option {#displays-option}
57 | This option can be useful for configuring monitors; however, it can be implemented as a separate module.
58 |
59 | ```nix
60 | {delib, ...}:
61 | delib.module {
62 | name = "hosts";
63 |
64 | options = with delib; let
65 | host = {config, ...}: {
66 | options =
67 | hostSubmoduleOptions
68 | // {
69 | displays = listOfOption (submodule {
70 | options = {
71 | enable = boolOption true;
72 | touchscreen = boolOption false;
73 |
74 | # e.g. DP-1, HDMI-A-1
75 | name = noDefault (strOption null);
76 | primary = boolOption (builtins.length config.displays == 1);
77 | refreshRate = intOption 60;
78 |
79 | width = intOption 1920;
80 | height = intOption 1080;
81 | x = intOption 0;
82 | y = intOption 0;
83 | };
84 | }) [];
85 | };
86 | };
87 | in {
88 | host = hostOption host;
89 | hosts = hostsOption host;
90 | };
91 |
92 | home.always = {myconfig, ...}: {
93 | assertions = delib.hostNamesAssertions myconfig.hosts;
94 | };
95 | }
96 | ```
97 |
98 | ## Short Version {#short-version}
99 | Using `delib.hostNamesAssertions` is strongly recommended, but it can also be omitted.
100 |
101 | ```nix
102 | {delib, ...}:
103 | delib.module {
104 | name = "hosts";
105 |
106 | options = with delib; let
107 | host.options = hostSubmoduleOptions;
108 | in {
109 | host = hostOption host;
110 | hosts = hostsOption host;
111 | };
112 | }
113 | ```
114 |
--------------------------------------------------------------------------------
/docs/src/hosts/introduction.md:
--------------------------------------------------------------------------------
1 | # Introduction to Denix Hosts {#introduction}
2 | A Denix host is an attribute set returned by the function [`delib.host`](/hosts/structure), which enables or disables specific configurations depending on the value of the option `${myconfigName}.host`. It also passes the input attribute set of the `delib.host` function to the `${myconfigName}.host.${delib.host :: name}` option.
3 |
4 | In simple terms, this allows you to separate the NixOS, Home Manager, Nix-Darwin, and custom options configuration into those that apply only to the current host and those that apply to all hosts. For example, the former can be used to enable or disable certain programs, while the latter can be used to add the current host's SSH key to the `authorizedKeys` of all hosts.
5 |
6 | A host can also be compared to a module, because all hosts are imported regardless of which one is active, but the applied configurations depend on the active host.
7 |
8 | ## Options {#options}
9 | For hosts to work, the configuration must include the options `${myconfigName}.host` and `${myconfigName}.hosts`, which **you define yourself** in one of the modules.
10 |
11 | Here is an example of a minimal recommended host configuration:
12 |
13 | ```nix
14 | {delib, ...}:
15 | delib.module {
16 | name = "hosts";
17 |
18 | options = with delib; let
19 | host = {
20 | options = hostSubmoduleOptions;
21 | };
22 | in {
23 | host = hostOption host;
24 | hosts = hostsOption host;
25 | };
26 |
27 | home.always = {myconfig, ...}: {
28 | assertions = delib.hostNamesAssertions myconfig.hosts;
29 | };
30 | }
31 | ```
32 |
33 | More examples can be found in the [Examples](/hosts/examples) section.
34 |
--------------------------------------------------------------------------------
/docs/src/hosts/structure.md:
--------------------------------------------------------------------------------
1 | # Structure {#structure}
2 |
3 | ## Function Arguments {#function-arguments}
4 | - `name`: a string representing the host name.
5 | - `homeManagerSystem`: a string used in the `pkgs` attribute of the `home-manager.lib.homeManagerConfiguration` function, which is used in the [`delib.configurations`](/configurations/introduction) function as `homeManagerNixpkgs.legacyPackages.${homeManagerSystem}`.
6 | - `myconfig`: sets its value to `config.${myconfigName}` if `config.${myconfigName}.host` matches the current host.
7 | - `nixos`: sets its value to `config` if `moduleSystem` is `nixos` and `config.${myconfigName}.host` matches the current host.
8 | - `home`: sets its value to `config` if `moduleSystem` is `home` and `config.${myconfigName}.host` matches the current host. Otherwise, if `config.${myconfigName}.host` matches the current host, sets its value to `config.home-manager.users.${homeManagerUser}`.
9 | - `darwin`: sets its value to `config` if `moduleSystem` is `darwin` and `config.${myconfigName}.host` matches the current host.
10 | - `shared.myconfig`: sets its value to `config.${myconfigName}` for all hosts.
11 | - `shared.nixos`: sets its value to `config` if `moduleSystem` is `nixos`. Otherwise, does nothing.
12 | - `shared.home`: sets its value to `config` if `moduleSystem` is `home`. Otherwise, sets it to `config.home-manager.users.${homeManagerUser}`.
13 | - `shared.darwin`: sets its value to `config` if `moduleSystem` is `darwin`. Otherwise, does nothing.
14 |
15 | ## Passed Arguments {#passed-arguments}
16 | A list of arguments passed to `?(shared.)[myconfig|nixos|home|darwin]` if their type is `lambda`:
17 |
18 | - `name`: the same `name` as in the arguments of `delib.host`.
19 | - `myconfig`: equals `config.${myConfigName}`.
20 | - `cfg`: equals `config.${myConfigName}.hosts.${delib.host :: name}`.
21 |
22 | ## Pseudocode {#pseudocode}
23 | ```nix
24 | delib.host {
25 | name = "";
26 |
27 | # homeManagerNixpkgs.legacyPackages.${homeManagerSystem}
28 | homeManagerSystem = "x86_64-linux";
29 |
30 | # if config.${myconfigName}.host == name
31 | # then {config.${myConfigName} = ...;}
32 | # else {}
33 | myconfig = {name, cfg, myconfig, ...}: {};
34 |
35 | # if config.${myconfigName}.host == name, then
36 | # if moduleSystem == "nixos"
37 | # then {config = ...;}
38 | # else {}
39 | # else {}
40 | nixos = {name, cfg, myconfig, ...}: {};
41 |
42 | # if config.${myconfigName}.host == name, then
43 | # if moduleSystem == "home"
44 | # then {config = ...;}
45 | # else {config.home-manager.users.${homeManagerUser} = ...;}
46 | # else {}
47 | home = {name, cfg, myconfig, ...}: {};
48 |
49 | # if config.${myconfigName}.host == name, then
50 | # if moduleSystem == "darwin"
51 | # then {config = ...;}
52 | # else {}
53 | # else {}
54 | darwin = {name, cfg, myconfig, ...}: {};
55 |
56 | # config.${myConfigName} = ...
57 | shared.myconfig = {name, cfg, myconfig, ...}: {};
58 |
59 | # if moduleSystem == "nixos"
60 | # then {config = ...;}
61 | # else {}
62 | shared.nixos = {name, cfg, myconfig, ...}: {};
63 |
64 | # if moduleSystem == "home"
65 | # then {config = ...;}
66 | # else {config.home-manager.users.${homeManagerUser} = ...;}
67 | shared.home = {name, cfg, myconfig, ...}: {};
68 |
69 | # if moduleSystem == "darwin"
70 | # then {config = ...;}
71 | # else {}
72 | shared.darwin = {name, cfg, myconfig, ...}: {};
73 | }
74 | ```
75 |
--------------------------------------------------------------------------------
/docs/src/index.md:
--------------------------------------------------------------------------------
1 | ---
2 | # https://vitepress.dev/reference/default-theme-home-page
3 | layout: home
4 |
5 | hero:
6 | name: "Denix Documentation"
7 | text: "Nix Library for Configurations"
8 | tagline: "Denix provides tools for creating scalable NixOS, Home Manager, and Nix-Darwin configurations with modules, hosts, and rices"
9 | image:
10 | light: https://raw.githubusercontent.com/yunfachi/denix/master/.github/assets/logo_light.svg
11 | dark: https://raw.githubusercontent.com/yunfachi/denix/master/.github/assets/logo_dark.svg
12 | actions:
13 | - theme: brand
14 | text: Introduction
15 | link: /getting_started/introduction
16 | - theme: alt
17 | text: GitHub with Templates
18 | link: https://github.com/yunfachi/denix
19 |
20 | features:
21 | - title: Modules
22 | details: Custom modules contain options and related configurations, making it easy to manage the entire system
23 | - title: Hosts and Rices
24 | details: Hosts are unique configurations for each machine, while rices are customizations applicable to all hosts
25 | - title: NixOS, Home Manager, and Nix-Darwin
26 | details: NixOS, Home Manager, and Nix-Darwin configurations can be written in the same file, and Denix will automatically separate them
27 |
28 | ---
29 |
--------------------------------------------------------------------------------
/docs/src/modules/examples.md:
--------------------------------------------------------------------------------
1 | # Examples
2 |
3 | ## Constants {#constants}
4 | ```nix
5 | {delib, ...}:
6 | delib.module {
7 | name = "constants";
8 |
9 | options.constants = with delib; {
10 | username = readOnly (strOption "sjohn");
11 | userfullname = readOnly (strOption "John Smith");
12 | useremail = readOnly (strOption "johnsmith@example.com");
13 | };
14 | }
15 | ```
16 |
17 | ## Home Manager {#home-manager}
18 | With [constants](#constants):
19 | ```nix
20 | {delib, pkgs, ...}:
21 | delib.module {
22 | name = "home";
23 |
24 | home.always = {myconfig, ...}: let
25 | inherit (myconfig.constants) username;
26 | in {
27 | home = {
28 | inherit username;
29 | # If you don't need Nix-Darwin, or if you're using it exclusively,
30 | # you can keep the string here instead of the condition.
31 | homeDirectory =
32 | if pkgs.stdenv.isDarwin
33 | then "/Users/${username}"
34 | else "/home/${username}";
35 | };
36 | };
37 | }
38 | ```
39 |
40 | ## User {#user}
41 | With [constants](#constants):
42 | ```nix
43 | {delib, ...}:
44 | delib.module {
45 | name = "user";
46 |
47 | # If you're not using NixOS, you can remove this entire block.
48 | nixos.always = {myconfig, ...}: let
49 | inherit (myconfig.constants) username;
50 | in {
51 | users = {
52 | groups.${username} = {};
53 |
54 | users.${username} = {
55 | isNormalUser = true;
56 | initialPassword = username;
57 | extraGroups = ["wheel"];
58 | };
59 | };
60 | };
61 |
62 | # If you're not using Nix-Darwin, you can remove this entire block.
63 | darwin.always = {myconfig, ...}: let
64 | inherit (myconfig.constants) username;
65 | in {
66 | users.users.${username} = {
67 | name = username;
68 | home = "/Users/${username}";
69 | };
70 | };
71 | }
72 | ```
73 |
74 | ## Git {#git}
75 | With [constants](#constants):
76 | ```nix
77 | {delib, ...}:
78 | delib.module {
79 | name = "programs.git";
80 |
81 | options.programs.git = with delib; {
82 | enable = boolOption true;
83 | enableLFS = boolOption true;
84 | };
85 |
86 | home.ifEnabled.programs.git = {myconfig, cfg, ...}: {
87 | enable = true;
88 | lfs.enable = cfg.enableLFS;
89 |
90 | userName = myconfig.constants.username;
91 | userEmail = myconfig.constants.useremail;
92 | };
93 | }
94 | ```
95 |
96 | ## Alejandra {#alejandra}
97 | ```nix
98 | {delib, ...}:
99 | delib.module {
100 | name = "programs.alejandra";
101 |
102 | options = delib.singleEnableOption true;
103 |
104 | home.ifEnabled.home.packages = [pkgs.alejandra];
105 | }
106 | ```
107 |
--------------------------------------------------------------------------------
/docs/src/modules/introduction-nixos.md:
--------------------------------------------------------------------------------
1 | # Introduction to NixOS Modules {#introduction-nixos}
2 | A NixOS module is a file containing a Nix expression with a specific structure. It defines options (options) and values for those options (config). For example, the `/etc/nixos/configuration.nix` file is also a module.
3 |
4 | Home Manager and Nix-Darwin modules work similarly, but they can be used not only in NixOS but also on other systems.
5 |
6 | This is not a comprehensive guide on Nix modules, so it is recommended to read the [NixOS Wiki article on modules](https://nixos.wiki/wiki/NixOS_modules).
7 |
8 | ## Structure {#structure}
9 | The structure of a NixOS module:
10 |
11 | ```nix
12 | {
13 | imports = [
14 | # Paths to other modules or Nix expressions.
15 | ];
16 |
17 | options = {
18 | # Declaration of options.
19 | };
20 |
21 | config = {
22 | # Assigning values to previously declared options.
23 | # For example, networking.hostName = "denix";
24 | };
25 |
26 | # However, values are usually assigned to options not in config, but here.
27 | # For example, networking.hostName = "denix";
28 | }
29 | ```
30 |
31 | ### Function {#structure-function}
32 | A module can also be a function (lambda) that returns an attribute set:
33 |
34 | ```nix
35 | {lib, ...} @ args: {
36 | # Formally, this is config._module.args.hostname
37 | _module.args.hostname = lib.concatStrings ["de" "nix"];
38 |
39 | imports = [
40 | {hostname, config, ...}: {
41 | config = lib.mkIf config.customOption.enable {
42 | networking.hostName = hostname;
43 | };
44 | }
45 | ];
46 | }
47 | ```
48 |
49 | ### Imports
50 | `imports` is a list of relative and absolute paths, as well as [functions](#structure-function) and attribute sets:
51 |
52 | ```nix
53 | {
54 | imports = [
55 | ./pureModule.nix
56 | /etc/nixos/impureModule.nix
57 | {pkgs, ...}: {
58 | # ...
59 | }
60 | ];
61 | }
62 | ```
63 |
64 | ### Nixpkgs Options
65 | Options are usually declared using `lib.mkOption`:
66 |
67 | ```nix
68 | optionName = lib.mkOption {
69 | # ...
70 | };
71 | ```
72 |
73 | `lib.mkOption` accepts an attribute set. Some attributes include:
74 |
75 | - `type`: the type of value for this option, e.g., `lib.types.listOf lib.types.port`.
76 | - `default`: the default value for this option.
77 | - `example`: an example value for this option, used in documentation.
78 | - `description`: a description of this option, also used in documentation.
79 | - `readOnly`: whether the option can be modified after declaration.
80 |
81 | For more information on Nixpkgs options, see the [NixOS Wiki](https://nixos.wiki/wiki/Declaration).
82 |
83 | ### Denix Options
84 | Denix uses a different approach to options, although both methods can be used simultaneously.
85 |
86 | An example of a module with options using Denix:
87 |
88 | ```nix
89 | {delib, ...}:
90 | delib.module {
91 | name = "coolmodule";
92 |
93 | options.coolmodule = with delib; {
94 | # boolOption
95 | enable = boolOption false;
96 | # noDefault (listOf)
97 | ports = noDefault (listOfOption port null);
98 | # allowNull (strOption)
99 | email = allowNull (strOption null);
100 | };
101 | }
102 | ```
103 |
104 | For more information on Denix options, see the [Options](/options/introduction) section.
105 |
106 | ## Creating Your Own Modules (Options) {#creating-own-modules}
107 | Declaring your own options is a great practice if you want to enable or disable certain parts of the code. This can be useful if you have multiple hosts (machines) with the same configuration, and, for example, machine `foo` does not need a program that is used on machine `bar`.
108 |
109 | An example of a NixOS module for simple git configuration:
110 |
111 | ```nix
112 | {lib, config, ...}: {
113 | options.programs.git = {
114 | enable = lib.mkEnableOption "git" // {default = true;};
115 | };
116 |
117 | config = lib.mkIf config.programs.git.enable {
118 | programs.git = {
119 | enable = true;
120 | lfs.enable = true;
121 |
122 | config = {
123 | init.defaultBranch = "master";
124 | };
125 | };
126 | };
127 | }
128 | ```
129 |
130 | The same configuration but using Denix:
131 |
132 | ```nix
133 | {delib, ...}:
134 | delib.module {
135 | name = "programs.git";
136 |
137 | options = delib.singleEnableOption true;
138 |
139 | nixos.ifEnabled.programs.git = {
140 | enable = true;
141 | lfs.enable = true;
142 |
143 | config = {
144 | init.defaultBranch = "master";
145 | };
146 | };
147 | }
148 | ```
149 |
--------------------------------------------------------------------------------
/docs/src/modules/introduction.md:
--------------------------------------------------------------------------------
1 | # Introduction to Denix Modules {#introduction}
2 | A Denix module is the same as a NixOS, Home Manager, or Nix-Darwin module, but its attribute set is wrapped in the [`delib.module`](/modules/structure) function.
3 |
4 | ## No Limitations {#no-limitations}
5 | This means that you can use all three types of modules simultaneously, although it's unlikely you'll need anything other than the first option:
6 |
7 | ### Denix Module
8 | ```nix
9 | {delib, ...}:
10 | delib.module {
11 | name = "...";
12 | }
13 | ```
14 |
15 | ### Denix Module with NixOS/Home Manager/Nix-Darwin Module
16 | ```nix
17 | {delib, ...}:
18 | delib.module {
19 | name = "...";
20 | } // {
21 |
22 | }
23 | ```
24 |
25 | ### NixOS/Home Manager/Nix-Darwin Module Only
26 | ```nix
27 | {
28 |
29 | }
30 | ```
31 |
32 | ## Simplicity and Cleanliness {#simplicity-and-cleanliness}
33 | Denix modules tend to look simpler and cleaner compared to NixOS/Home Manager/Nix-Darwin modules, due to the following reasons:
34 |
35 | 1. Simple yet fully functional option declaration (see [Options](/options/introduction)).
36 | 2. Built-in logic for separating configurations based on the value of `${delib.module :: name}.enable`: always, ifEnabled, ifDisabled.
37 | 3. Shared options but separated configurations for NixOS, Home Manager, Nix-Darwin, and custom options.
38 |
--------------------------------------------------------------------------------
/docs/src/modules/structure.md:
--------------------------------------------------------------------------------
1 | # Structure {#structure}
2 | This section uses the variables `myconfigName`, `moduleSystem`, and `homeManagerUser`, so it's recommended to first review the corresponding subsection: [delib.configurations Function Arguments](/configurations/structure#function-arguments).
3 |
4 | ## Function Arguments {#function-arguments}
5 | - `name`{#function-arguments-name}: string. It is recommended that it matches the parent path of the module's `enable` option, such as `"programs.example"`, since the `cfg` argument depends on this path.
6 | - `options`: attrset or a lambda that returns an attrset (see [Options](/options/introduction)).
7 | - `[myconfig|nixos|home|darwin].[ifEnabled|ifDisabled|always]`: attrset or a lambda that returns an attrset.
8 | - `myconfig.*`: sets values in `config.${myconfigName}`.
9 | - `nixos.*`: sets values in `config` if `moduleSystem` is `nixos`. Otherwise, does nothing.
10 | - `home.*`: sets values in `config` if `ModuleSystem` is `home`. Otherwise, sets it in `config.home-manager.users.${homeManagerUser}`.
11 | - `darwin.*`: sets values in `config` if `moduleSystem` is `darwin`. Otherwise, does nothing.
12 | - `[myconfig|nixos|home|darwin].ifEnabled`: executed only if the `cfg.enable` option (see [Passed Arguments - cfg](#passed-arguments-cfg)) exists and is `true`.
13 | - `[myconfig|nixos|home|darwin].ifDisabled`: executed only if the `cfg.enable` option exists and is `false`.
14 | - `[myconfig|nixos|home|darwin].always`: always executed, even if the `cfg.enable` option doesn't exist.
15 |
16 | ## Passed Arguments {#passed-arguments}
17 | A list of arguments passed to `options` and `[myconfig|nixos|home|darwin].[ifEnabled|ifDisabled|always]`, if their type is a `lambda`:
18 | - `name`: the same [name](#function-arguments-name) from the `delib.module` arguments.
19 | - `myconfig`: equals `config.${myConfigName}`.
20 | - `cfg`{#passed-arguments-cfg}: equals the result of the expression `delib.getAttrByStrPath name config.${myConfigName} {}`, where `name` is the [argument](#function-arguments-name) from `delib.module`, and `{}` is the value returned if the attribute is not found.
21 |
22 | ## Pseudocode {#pseudocode}
23 | ```nix
24 | delib.module {
25 | name = "";
26 |
27 | # options.${myConfigName} = ...
28 | options = {name, cfg, myconfig, ...}: {};
29 |
30 | # config.${myConfigName} = ...
31 | myconfig.ifEnabled = {name, cfg, myconfig, ...}: {};
32 | myconfig.ifDisabled = {name, cfg, myconfig, ...}: {};
33 | myconfig.always = {name, cfg, myconfig, ...}: {};
34 |
35 | # if moduleSystem == "nixos"
36 | # then {config = ...;}
37 | # else {}
38 | nixos.ifEnabled = {name, cfg, myconfig, ...}: {};
39 | nixos.ifDisabled = {name, cfg, myconfig, ...}: {};
40 | nixos.always = {name, cfg, myconfig, ...}: {};
41 |
42 | # if moduleSystem == "home"
43 | # then {config = ...;}
44 | # else {config.home-manager.users.${homeManagerUser} = ...;}
45 | home.ifEnabled = {name, cfg, myconfig, ...}: {};
46 | home.ifDisabled = {name, cfg, myconfig, ...}: {};
47 | home.always = {name, cfg, myconfig, ...}: {};
48 |
49 | # if moduleSystem == "darwin"
50 | # then {config = ...;}
51 | # else {}
52 | darwin.ifEnabled = {name, cfg, myconfig, ...}: {};
53 | darwin.ifDisabled = {name, cfg, myconfig, ...}: {};
54 | darwin.always = {name, cfg, myconfig, ...}: {};
55 | }
56 | ```
57 |
--------------------------------------------------------------------------------
/docs/src/options/introduction.md:
--------------------------------------------------------------------------------
1 | # Introduction to Denix Options {#introduction}
2 | Denix options are a wrapper for `lib.mkOption`. This means that any Denix option can be created using the standard `lib.mkOption`, and using Denix options is optional.
3 |
4 | ## Why use Denix options? {#why}
5 | Using `lib.mkOption` can be cumbersome, and writing something like this every time:
6 |
7 | ```nix
8 | lib.mkOption {type = lib.types.listOf lib.types.str; default = [];}
9 | ```
10 |
11 | is inconvenient, especially when options are used extensively in your configuration. Instead, you can write something more concise:
12 |
13 | ```nix
14 | delib.listOfOption delib.str []
15 | ```
16 |
17 | Thus, instead of creating an option by specifying all parameters, you can use Denix functions for more readable and cleaner code.
18 |
19 | ## Working Principle {#principle}
20 | Functions related to options are divided into four main types:
21 |
22 | ### Creating an Option with Type N
23 | - `*Option ` - for example, `strOption "foo"`.
24 | - `*OfOption ` - for example, `listOfOption str ["foo" "bar"]`.
25 | - `*ToOption ` - for example, `lambdaToOption int (x: 123)`.
26 |
27 | ### Adding Type N to Option Type X
28 | - `allow*