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 nullOr option becomes a "Configure / use the default" toggle rather than a bare oneOf variant picker; an attrTag discriminated union becomes a single tag <select> with only the chosen branch's fields below it (retaining shared fields across a switch); an attrsOf map's new-key input accepts the Nix attrName key 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 attrsOf map, a listOf of submodules, a nullOr or attrTag object -- 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.