I've found the Nix language to be a really useful configuration language, even "outside" of the NixOS ecosystem. I reuse nixpkgs's module system, but to describe things that are used outside of the NixOS system (for example in an Ansible playbook).<p>For example, I'm using it to describe a set of containers and services in my infrastructure, and it allows me to properly describe the interfaces between the different components of the infrastructure, using several modules :
- a "base" module defines the options used for describing the services
- one defines the services themselves
- one handles the reverse proxy configuration for these services (for multiple frontends), as well as the SSL certificates and DNS zones
- one handles the containers themselves (through Docker or LXD)
- one handles the networking overlay
- one handles the "shared services" (databases, caches, etc)<p>Each of these modules is basically a function that takes the resulting configuration as argument, allowing it to reuse values defined by the other modules, and the configuration itself is the fixpoint of the composition of all of these functions.<p>It all composes quite well, and the nixpkgs module system allows me to document the options provided by each module. I can even reuse some of the existing NixOS to create a web interface where other admins can search for configuration options and lookup their documentation. Some things are exported in JSON, some are used directly as NixOS modules, some things source the inventory for Ansible playbooks, etc.<p>It allowed me to create a well-defined source of truth for a very heteregenous architecture, while preserving some of the existing workflows and tooling.<p>It's not ideal of course : Nix itself is not typed, the nixpkgs module system provides some typing, but the integration is not perfect, and this makes error handling quite tedious. Also, the interpreter is quite slow, there is no documented way to embed it into your own program, and I