Passing .env to a flake

I have a flake which outputs a nixosConfigurations.foobar entry.
I use nixos-rebuild --flake to deploy that config to a server.

Depending on whether I am pushing to prod or to my test environment I’d like to pass a different set of variables into the configs specialArgs. Preferrably through the use of a .env file, as is common in web projects.

Is there a mechanism that allows me to do that?

Don’t do that. Instead make two (or more) different nixosConfiguration entries, and call e.g. nixos-rebuild --flake path#dev and nixos-rebuild --flake path#prod depending on where you’re deploying to.

Also don’t use specialArgs to make changes between the configurations, just import a different module.

2 Likes

Agreed, the point of the .env is so you can declare conditions in the environment. Just declare them in the proper first-party supported mechanism of a nixos module.

Right, because an output of a flake should be free of side-effects.

In that case I will just code a small utility function that selectively adds the dev, test or prod variables and creates nixosConfiguration members with a -<environment> postfix.

Is there a good way to read those from a .env file tough?
Or is that not a good idea because it needs to be checked into git?
I am not using those files to store secrets, it’s just different IPs, hostnames and device names for each environment that do not really belong in the git repo.

You could write a .env parser in nix, but this isn’t a good idea, since:

A .env file is inherently a singleton value; you cannot change the contents without changing the code.

Of course, you could change it to a directory and have .env/prod and .env/test files and suchlike, and then write an even more complex parser, but now you’re just reinventing the module system.


Rather than getting stuck on .env files, my suggestion is to learn how to use the module system effectively. It’s a pretty common thing for newcomers to not fully grok the module system and then attempt workarounds like this.

If you’d like, feel free to share your code at least in terms of entrypoints/basic high-level module contents and what needs to be different, I’d be happy to show what I mean with a practical example.

1 Like

Ah, well, yeah, those things actually do belong in the git repo since the git repo inherently describes the full machines. It might be cleaner to have that configuration in a separate per-machine module, but it is definitely needed by nix and should be part of your configuration.

That, or you should write configuration that sets up runtime services to assign those things dynamically (e.g. via dhcp).

I do know my way around the module system. I am deliberately trying to keep nix out of certain things, because I have learned that using nix for everything costs me a lot of time, much more so than just using an industry standard solution.

In this case I am using terraform to spawn vms and nixos to define the system that runs on those vms. I want to use the values defined in .env for both.

But you are right that those values belong in the git repo.
Maybe I can use builtins.fromToml to parse the .env file.

systemd.services.<name>.serviceConfig.EnvironmentFile maybe?

That makes a systemd service evaluate the file at runtime, which is what @TLATER suggested.
In that case I would have to put the file on some volume that my VM can see and mount it using i.e. terraform. Which is possible, but not really what I want to do, because I want to use the variables in i.e. `services.nextcloud.hostName`.

Checking the values into git is the correct solution here since there is actually 3 different nixos configurations, one for each environment.

You’re building something quite bespoke then.

IMO for a clean answer you need to determine what the (original) source of truth for values like services.nextcloud.hostName should be - if it’s nix, define it with the module system, if not, define it dynamically (potentially by writing your own NixOS modules instead of using nixpkgs’).

Having two sources of truth like you’re proposing with .env is just going to cause you headaches.

You can copy the file onto the system by copying it to the nix store, i.e. ./test.env