Application with backend and frontend, how to flakeify

As the title says, I have an application that’s separated into backend (Python) and frontend (Elm). Currently, my directory structure looks like this:


To link the frontend and backend, I do (in the backend Python package derivation):

postInstall = ''
  wrapProgram $out/bin/webserver --set STATIC_FOLDER ${frontend}/


frontend = pkgs.callPackage (import ./frontend/default.nix) {};

Now I want to transition to flakes.

Writing a flake for the backend is easy. But how do I turn the frontend into a flake? Write frontend/flake.nix and connect the two? I’d love to retain the ability to have a devshell for the Python backend and the Elm frontend, separately.

1 Like

I now have a flake.nix in both ./ and ./frontend. In ./ I say:

inputs.frontend.url = "frontend/";

and then include the frontend in the backend build process.

This works, but I get the following messages every time I do nix develop:

warning: Git tree '/home/pmidden/code/myproject' is dirty
warning: updating lock file '/home/pmidden/code/myproject/flake.lock':
• Updated input 'frontend':
    'path:/nix/store/6agz70y56w4dczsqq750m91xc1aflip3-source/frontend?lastModified=1&narHash=sha256-WWKNhQs%2fWVNEDh4givYSpkkyvA6jw4Wp06WGmNC7qOk=' (1970-01-01)
  → 'path:/nix/store/ilhvsrydmiln0x0xz7q7ncamkybbg0i4-source/frontend?lastModified=1&narHash=sha256-WWKNhQs%2fWVNEDh4givYSpkkyvA6jw4Wp06WGmNC7qOk=' (1970-01-01)
warning: Git tree '/home/pmidden/code/myproject' is dirty

Any idea why that is?

  1. This is because its absolute location in the filesystem changes constantly
  2. using relative paths as a flake input is massively dependant on your version, the semantics of such “subflakes” are massively in flux and may work differently or not at all on the next update of your nix version.
1 Like

I see, thanks for your answer! This sounds like such an approach could be considered “discouraged”, at least right now.

So a better idea might be to…merge the flakes together to create one flake for frontend and backend? But then I would like to have two devshells at least.

Aren’t you already maintaining 2 different dev shells?

I do not see how it would be a problem having them in a single flake rather than 2 different ones.

1 Like

Hm! I thought you could only have one devShell attribute.

Currently, I have two flake.nix, one in frontend/, one in ./.

Yes, there can only be a single devShell.${system} attribute, though that has been deprecated with nix 2.8 IIRC.

You are supposed to use devShells.${system}.${name} now, where ${name} can be freely choosen and will be tried by nix develop .#$name first. There is the special name default, which will be tried when there is no name given in the fragment.


I do what @NobbZ describes: tlaternet-webserver/flake.nix at master - tlaternet-webserver - Gitea: Git with a cup of tea

I then put .envrc files that use flake path:..#<shell-name> to load the correct language servers and whatnot for the sub-project, which seems to work well with emacs’ direnv integration at least. I’ve had many iterations of this project, I ultimately arrived at this and think it’s as close to perfect as possible.

dream2nix needs some work to for this to truly be usable, but if you avoid it/don’t use npm you should be good to go.

This overall has the advantage that I can put integration tests in my flake checks and not have to work with awkward indirection for the project. nix run just building and running my front- and backend together is convenient too, especially since changes to one often require changes in the other.

Splitting this into two flakes requires updating inputs constantly, which is inconvenient.

1 Like

Thanks, I basically copied your approach here and it’s working perfectly (it’s nice to see a fellow direnv/emacs user :D).

Also thanks @NobbZ for the explanation, wouldn’t have understood @TLATER’s snippet otherwise.

Edit: I had to update to Nix-2.11, too, btw.

Hm, odd, I’m on 2.8. What forced you to upgrade specifically, for reference?

1 Like

Nix told me that the flake doesn’t provide devShells.x86_64.frontend, although it clearly did. I was on 2.10 at that time.

You could use flake-parts to split your flake into modules. The real flake at the root can then import flake attributes from anywhere in the repo - e.g. from your frontend. That way you can have separation of concerns and keep your expressions close to your code.

It’s still just one flake, so you won’t have duplicate dependencies, but you’ll still want something like a .envrc to tell the tooling which devShell attribute to use in which directory.