How are flakes supposed to be used?

Sorry for what might be a dumb question, but I was wondering about the correct way to use flakes. I have the following flake.nix file:

{
  description = "A simple NixOS flake";

  inputs = {
    # Nixpkgs repos
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; # "github:NixOS/nixpkgs/nixos-24.05"
    nixpkgs-stable.url = "github:NixOS/nixpkgs/nixos-24.05";
    nixpkgs-unstable.url = "github:NixOS/nixpkgs/nixos-unstable-small";

    # NixOS Hardware repo
    nixos-hardware.url = "github:NixOS/nixos-hardware/master";

    # Home Manager repo
    home-manager = {
      #url = "github:nix-community/home-manager/release-24.05";
      url = "github:nix-community/home-manager/master";
      inputs.nixpkgs.follows = "nixpkgs";
    };

    # Secure boot repo
    lanzaboote = {
      url = "github:nix-community/lanzaboote/v0.4.1";
      inputs.nixpkgs.follows = "nixpkgs";
    };

    agenix = {
      url = "github:ryantm/agenix";
      inputs.nixpkgs.follows = "nixpkgs";
    };

    # VPN confinement repo
    vpn-confinement = {
      url = "github:Maroka-chan/VPN-Confinement";
      inputs.nixpkgs.follows = "nixpkgs";
    };

    # Nixarr repo (test)
    #nixarr.url = "github:rasmus-kirk/nixarr";
  };

  outputs = inputs@{
        nixpkgs,
        home-manager,
        lanzaboote,
        agenix,
        #vpn-confinement, # works
        #nixarr,
        ... 
  }: {
    nixosConfigurations = {
      homeserver = nixpkgs.lib.nixosSystem {
        system = "x86_64-linux";

        modules = [
          ./hosts/server/configuration.nix

          # Start lanzaboote configuration
          lanzaboote.nixosModules.lanzaboote

          ({ pkgs, lib, ... }: {
            environment.systemPackages = with pkgs; [
              pkgs.sbctl
            ];

            boot.loader.systemd-boot.enable = lib.mkForce false;

            boot.lanzaboote = {
              enable = true;
              pkiBundle = "/etc/secureboot";
            };
          })

          # Start Agenix configuration
          agenix.nixosModules.default

          # Start Home Manager configuration
          home-manager.nixosModules.home-manager {
            home-manager = {
              useGlobalPkgs = true;
              useUserPackages = true;
              users.server = import ./modules/home/defaults.nix;
            };
          }

          #vpn-confinement.nixosModules.default
          #nixarr.nixosModules.default
        ];
      };
    };
  };
}

Is this the correct way to use them? As you can probably see, I used the lanzaboote flake provided on their quick start-guide over at GitHub and baked it into my personal flake; however, looking over at MicroVM’s GitHub repo, and the complexity of their flake, I am having doubts on whether the way I’ve written my flake is correct or not.

If it isn’t the correct way, can someone chip in on the correct way of using flakes?

The provided code seems syntactically valid at a glance. Microvm flake file is using flake-utils machinery to automate boilerplate generation which is not strictly needed in general and not needed at all for nixosConfigurations output.

Shameless plug: here’s a post on flake.nix file structure. It has sections on nixosConfigurations and flake-utils.

1 Like

Thanks for the input. I have read your post, but I have to say that a lot of it is “Greek” to me :laughing: I have no experience with functional programming; Nix is thus my first attempt at it, and I have been using it for about two weeks or so. I love the way it works and the issues it solves, but its learning curve is more or less vertical…

That being said. the code I posted works: it compiles and functions exactly as expected, but I am trying to abstract some of the code in order not to bloat the configuration files. Which is why I was wondering if it is possible to dynamically import a flake - instead of embedding it - into mine.

Careful not to veer too far into premature optimization which is the root of all evil. Getting too creative with the code sometimes results in a spike of wtfs/minute when the code breaks. That being said, it’s your computer and your code. Hack away.

I assume by “importing a flake” you mean getting your code depend on a different flake:

Using inputs (the way you’re doing it) is how it should be done. While there are other mechanisms (getFlake, for example) they aren’t for standard usage. Typically they break the purity and come with gotchas.

If by “importing a flake” you mean “importing a module from a different flake”, you could leverage specialArgs argument for nixosSystem (see this thread for details and links).

Offtopic but I’d be happy to get feedback on which parts could be explained better. Feel free to send a DM or an email.

If I recall correctly, nix-the-language clicked for me when I understood that it’s execution model is one that computes a fix point – i.e. it tries to merge attribute sets, evaluate and resolve attributes until the value finally becomes constant and cannot be evaluated further (usually the good result) or it enters infinite recursion (and spews errors).

1 Like

Your flake looks fine. You are not writing it to distribute a platform to provision and run multiple virtual machines using a plethora of hypervisors and storage backends like microVM does. You write it to configure one system.

Obviously, it’s going to be simpler. Also, I found Nix code is relatively easy to refactor into modules later. I would only worry about doing that once you actually would need to copy a large chunk to, e.g., add a second system to that flake.