Overview
A Vue + JSONForms widget bundle that renders a NixOS-module-derived JSON Schema and highlights each field that differs from a baseline, the value in effect (for example, the last deployed configuration).
The pipeline
The name is a little misleading, so it is worth being blunt about what this
repository does and does not do: it evaluates no Nix. There is no NixOS
module here, nothing imports nixpkgs.lib, and nothing reads a .nix file at
runtime. It is a JavaScript bundle that consumes a JSON Schema.
Turning a NixOS module into a working web form takes two libraries, and neither does it alone:
NixOS module
|
| module-schema (optionsToSchema) <- evaluates the module system
v
JSON Schema
|
| nix-module-form (this repo) <- renders it, no Nix involved
v
edited JSON value
|
| the embedder <- validates and writes it back
v
Nix configuration
The upstream half is
fediversity/module-schema
(docs), which converts
lib.types option declarations into JSON Schema. This half renders that schema
and hands back an edited value. The two are deliberately separable: the
generator is useful without a form, and the form is useful against any
Nix module-shaped JSON Schema.
The downstream half -- deciding what a submit does, where the value is stored, who is allowed to submit -- belongs to whoever embeds the widget. See Usage.
What this adds over stock JSONForms
Pointing vanilla JSONForms at a generated schema gets you a form, but not one for which NixOS option types map cleanly onto the shapes a generic renderer expects. This bundle adds:
- Nix module-shaped renderers. A
nullOroption becomes a "Configure / use the default" toggle rather than a bareoneOfvariant picker; anattrTagdiscriminated union becomes a single tag<select>with only the chosen branch's fields below it (retaining shared fields across a switch); anattrsOfmap's new-key input accepts the NixattrNamekey type, which a default AJV rejects. The full contract is in schema shapes. - A diff against a baseline. Every field is highlighted against the baseline, the value in effect (for example, the last deployed configuration) -- added, changed, or reverted -- rather than against whatever the form happened to load. On top of that sits a schema-change layer: which options were added, removed, renamed, or retyped since the baseline was set, with the old value shown read-only beside the new field.
- Collapsible sections. A module tree becomes a few hundred controls in one
column. Each object section -- a submodule, an
attrsOfmap, alistOfof submodules, anullOrorattrTagobject -- renders behind a header the user opens, and the sections that hold a change, a schema change, or a rejected field open themselves. See collapsible sections. - NixOS-aware validation. Schema defaults are deliberately not filled into the value, so an absent key keeps meaning "follow the Nix default" instead of freezing today's default into the stored config.
Who uses it
The fediversity panel is the real-world consumer: it pins this repo, supplies its own entry adapter, and connects the form to its own backend. This repository was extracted from that monorepo so the widget can version and ship on its own.
Where to go next
- Usage -- pinning, building, mounting, the API reference, the schema shapes, and the gotchas.
- Demo -- two self-contained pages running the whole pipeline.
- Comparison -- how this relates to clan, nixos-conf-editor, thymis, and other Nix-configuration UIs.
- Flake attributes -- this repo's own outputs.
- Specifications -- what the widget does, and the principles that apply to all changes.