Open-source project
oddlama/nix-topology avatar
oddlama/nix-topology

nix-topology: infrastructure diagrams generated from your NixOS configuration

🍁 Generate infrastructure and network diagrams directly from your NixOS configurations

1,024 stars45 forksNixMIT

At a glance

What is it?
nix-topology renders SVG infrastructure and network diagrams directly from NixOS configurations, collecting interfaces from systemd-networkd, guests from microvm.nix and nixos containers, and network information from kea. Physical connections and external devices are not derivable from configuration, so those are declared by hand in a separate topology module.
Who is it for?
Adopt nix-topology if you run a multi-host NixOS setup and your infrastructure diagram is currently out of date, and you are willing to declare the physical layer by hand. Do not adopt it if your hosts are not NixOS, since the collection depends entirely on NixOS configuration.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 3 days ago.
What is it written in?
Mainly Nix, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The diagram that was never updated

nix-topology generates infrastructure and network diagrams as SVGs directly from your NixOS configurations, and the reason it exists is in the Why section, which is worth quoting in spirit. The author became envious of all the manually crafted infrastructure diagrams on the r/homelab subreddit, and then asked who has time for that, and decided to spend a whole lot more time to create a generator that he would use once or twice in his life. The README adds that maybe it will be useful for somebody else too.

That framing matters, because it sets expectations. This is not a documentation pipeline you are meant to run on every commit. It is a tool that takes a configuration you already have and turns it into a picture, so that the picture can be regenerated in an afternoon rather than maintained by hand forever.

The output is two diagrams rather than one. There is a main diagram of physical connections and a network-centric diagram, and the documentation site shows both side by side for a complex example. The examples/ directory holds self-contained examples, with a simple/ and a complex/ case, so you can see what a small and a large topology look like before wiring it into your own flake.

The project is MIT licensed, written in Nix, the home page is oddlama.github.io/nix-topology, and the last push to the repository was on 2026-06-22. There are no GitHub releases, so the flake reference is the version mechanism, and the default branch is main.

What it extracts automatically, and what it cannot

The list of what nix-topology extracts is the technical core, and it is short enough to enumerate.

Interfaces come from systemd-networkd. Known configured services are collected. Guests come from microvm.nix, which is the framework for running NixOS virtual machines, and from nixos containers. Network information comes from kea, which is the DHCP server. Beyond extraction, it renders both the main diagram and the network-centric diagram, it automatically propagates assigned networks through your connections, and it lets you add external devices like switches, routers, and printers.

The distinction between what is derived and what is declared is the important design point, and the documentation is clear about it. After rendering for the first time, the initial diagram might look a little unstructured, and that is simply because nix-topology is missing some important connections that cannot be derived from a bunch of NixOS configurations, like physical connections. You will probably also want to add common devices like an image for the internet, switches, routers, and similar.

That split is a direct consequence of the source of truth. A hostname, an IP address, an interface, a running container, and a DHCP reservation are all facts that exist in the configuration and can be read. A cable running from one switch port to another is a physical fact that no configuration file records, and a switch sitting under the desk is not a NixOS host at all. The tool automates the half that can be automated and asks you to declare the half that cannot.

The automatic propagation of networks through connections is the feature that ties the two halves together. Once you declare that node1.lan is physically connected to node2.wan, and you have declared that both interfaces are on a network, the tool can work out the topology from there without you restating it per node.

Five steps, and the one that is slow

The installation is a flake with a global module system, and the steps are explicit.

First, add nix-topology as an input to your flake:

nix
inputs.nix-topology.url = "github:oddlama/nix-topology";

Second, add the exposed overlay to your global package definition so the rendering tools are available:

nix
pkgs = import nixpkgs {
  inherit system;
  overlays = [nix-topology.overlays.default];
}

Third, import the NixOS module in your host configurations:

nix
nixosConfigurations.host1 = lib.nixosSystem {
   system = "x86_64-linux";
   modules = [
     ./host1/configuration.nix
     nix-topology.nixosModules.default
   ];
}

Fourth, create the global topology by using topology = import nix-topology { pkgs = /*...*/; } and expose it as a flake output.

Fifth, render the topology with nix build .#topology.x86_64-linux.config.output, and the resulting directory contains the finished SVGs.

That last step carries the warning, and it is the practical constraint. The note says that this can take a minute depending on how many hosts you have defined, and that evaluating many nixos configurations just takes some time, and that the renderer sometimes struggles with handling bigger PNGs in a timely fashion.

Both halves of that are worth taking seriously. Evaluating a NixOS configuration is not free, and a topology covering fifty hosts means evaluating fifty systems. And the renderer is doing layout work on images, so the size of the PNGs you use for your device icons is a direct input to how long the build takes.

The flake-parts version, and the module system underneath

The project offers two ways to write the flake, and the difference is the module system you already use.

The plain version defines topology as a flake output computed with flake-utils.lib.eachDefaultSystem, so the topology is built per system. The flake-parts version is much shorter, because the module system handles the per-system repetition:

nix
{
  inputs.flake-parts.url = "github:hercules-ci/flake-parts";
  inputs.nix-topology.url = "github:oddlama/nix-topology";
  outputs = inputs:
    inputs.flake-parts.lib.mkFlake {inherit inputs;} {
      imports = [
        inputs.nix-topology.flakeModule
      ];
      perSystem = {...}: {
        topology.modules = [
          {
            # Your global topology definitions
          }
        ];
      };
    };
}

The key line is topology.modules, which is where your global topology definitions go. The comment in the plain flake version explains the shape of the global module, that your own file to define global topology works in principle like a NixOS module but uses different options, and that an inline module informs the topology of your existing NixOS hosts by passing nixosConfigurations = self.nixosConfigurations.

So there are two module systems in play, deliberately. The NixOS module is imported into each host, and that is where the host contributes what it knows about itself. The topology module is a separate, global module where you declare the things that are not per host, such as the networks and the physical connections between them. The documentation has a whole chapter on defining additional things for that part.

The repository layout reflects the separation. There is a nixos/ directory for the NixOS module, a topology/ directory for the global module, an options/ directory, and a flake-module.nix for the flake-parts integration.

Declaring connections, networks, and external devices

The shape of the global topology module is shown in a short example, and it is worth reading because it shows how little you have to write for a real connection.

nix
# This is a topology module, so use it in your global topology, or under `topology = {};` in any participating NixOS node
{
  # Connect node1.lan -> node2.wan
  nodes.node1.interfaces.lan.physicalConnections = [{ node = "node2"; interface = "wan"; }];
  # Add home network
  networks.home = {
    name = "Home Network";
    cidrv4 = "192.168.1.1/24";
  };
  # Tell nix-topology that myhost.lan1 is part of this network.

Three things are happening in those lines. A physical connection is declared from node1's lan interface to node2's wan interface, and the interface names match the ones that came out of the systemd-networkd configuration, so the connection attaches to real interfaces rather than to invented ones. A network is defined with a display name and a CIDR. And then a node's interface is assigned to that network, after which the network propagates along the connections automatically.

The comment at the top is the important structural note. The same block works in your global topology, or under topology = {}; in any participating NixOS node, which means a connection that only concerns two specific hosts can be declared locally, next to the host it concerns, instead of in the global file.

That is the difference between a tool that needs a separate file you maintain and one that lives with the configuration it describes. And it is the reason the initial diagram can look unstructured and then be fixed incrementally, one physical connection at a time, rather than being designed all at once.

Editorial conclusion

Adopt nix-topology if you run a multi-host NixOS setup and your infrastructure diagram is currently out of date, and you are willing to declare the physical layer by hand. Do not adopt it if your hosts are not NixOS, since the collection depends entirely on NixOS configuration. Verify first how long the build takes on your own configuration, because evaluating many NixOS systems is the slow part and the documentation warns about it.

Frequently asked questions

What does nix-topology generate?

SVG infrastructure and network diagrams generated directly from your NixOS configurations. It renders both a main diagram of physical connections and a network-centric diagram, and it lets you add external devices like switches, routers and printers.

What information does nix-topology extract automatically?

Interfaces from systemd-networkd, known configured services, guests from microvm.nix and from nixos containers, and network information from kea. Physical connections between hosts cannot be derived from configuration and have to be declared by hand in the topology module.

How do I render the topology?

Run nix build .#topology.x86_64-linux.config.output, and the resulting directory contains the finished SVGs. The documentation warns that this can take a minute depending on how many hosts you have defined, since evaluating many NixOS configurations takes time.

How do I declare a physical connection and a network?

In the global topology module, or under topology = {}; in any participating NixOS node. You add a physicalConnections entry naming the node and interface on each side, define a network with a name and a CIDR, and assign an interface to it, after which the network propagates through your connections automatically.

Does nix-topology work with flake-parts?

Yes. A flake-parts module is available alongside the plain flake, where you import the nix-topology flakeModule and define your global topology under topology.modules in the perSystem block.

Official sources

  1. Issues
  2. License: MIT
  3. oddlama/nix-topology on GitHub
  4. Project website
  5. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/oddlama-nix-topology.svg)](https://hysenlabs.com/projects/oddlama-nix-topology)

Was this useful?