I’m just passing by quickly, but I can answer your last questions.
You can spit out whatever outputs you want, so you could put either of those two final snippets. But they wouldn’t work, because they don’t match the conventional outputs that NixOS looks for. By convention, modules go under nixosModules
–and, since a single flake can have many modules, it’ll be looking for named modules. That makes the last snippet ‘wrong’ (because NixOS will ignore the user
attribute, you’ll just get a warning about “unrecognized output ‘users’”) and the second-from-last ‘wrong’ because user
isn’t a valid module, since it’s not a function.
It’s necessary to have a conventional place to store modules, because there are other types of output, for example your nixosConfigurations.myserver
output (or overlays, or shells, …). Without putting it in the right place, Nix doesn’t know if it’s supposed to be a module, a system config, or what.
myconfig
is just a name. It can be whatever you want. So a valid nixosModules entry might be:
outputs = { self, nixpkgs, ... }: {
nixosModules = { // <---- NixOS will, by convention, be looking under here for modules
mySuperUserModule = { ... }: { // <-- This is a function capable of accepting `config`, `lib`, etc--see below--so it's a valid module
config = {
users.users = {
// ... etc ...
};
// ... etc ...
};
};
};
};
I think maybe you’re getting that error because your myconfig
module isn’t a function. A module has to accept a bunch of arguments (config
, lib
, pkgs
, and some less commonly-used ones) to be valid.
There’s a few different ways to specify the arguments that the module will accept:
mymodule = _: { ... <insert config here> .... };
Take one argument and ignore it.
mymodule = args: { ... <insert config here> ... };
Take one argument and name it args
…you’ll find that args.config
, args.lib
, and args.pkgs
all exist (because you’re being passed a single attrset, basically a hashtable, with those attributes).
mymodule = { config, lib, pkgs }: { ... <insert config here> ... };
Take a single attrset argument, which must have config
, lib
, and pkgs
attributes, and nothing else (for which reason, I think this wouldn’t actually work–there are probably other args).
mymodule = { config, ... }: { ... <insert config here> ... };
Take a single attrset argument which must have config
, and can have whatever other attributes the caller feels like passing (which we’re just going to ignore). If you need to use packages, you could use { config, pkgs, ... }:
instead, for example.
So one way or another, your module must be a function, and it must be able to take a bunch of arguments (including those three I keep repeating), whether you intend to use them or not.
One final note: you may notice I stuck an extra config = { ... }
in your module definition. That wasn’t strictly necessary: if you skip it, Nix will usually figure out (using a hack of some kind) what you meant and treat the top-level like config. Later, though, when you start using options and imports, it’ll get confusing… I think it’s simpler to just say that a module is a function from { config, pkgs, lib, ...}
and to { config, ... }
.