Making globally available devshells

Heyo peeps,

I’ve been working on and off on my nixos journey, applying best practices as I learn along.

What I settled with is the idea of a “motherflake”: a single flake in a git repo that will contain everything I ever want as code. In particular, this motherflake contains the nixosconfigurations for all my machines, be it workstations or servers. My current attempt is here: GitHub - Chewie/motherflake: The Nixos flake to handle all of Loutre Telecom's configuration management

Keen eyes will notice a big problem in my config: everything is installed as packages, even stuff that should be a devshell. I didn’t notice this problem until I needed to install a C development library (cgreen): with nix-shell -p cgreen, I can compile; but if I put it as a package in my nixos config it fails, because the appropriate env vars are not updated.

So after going back to the drawing board, I learned about devshells and I think that’s what I need. However, my needs are a bit different than the usual use case: as a teacher, I don’t just have a few projects I’m working on that deserve their own devshell in the flake of their repository, but I tend to create lot of small temporary “projects” on the fly when I want to demonstrate something quickly. I don’t want to have to define the same devshell over and over, instead I’d like to have a collection of basic devshells with sane defaults for various languages that I can use for those cases.

Unfortunately, from what I understand it doesn’t look like I can “install” devshells or make them part of a nixos configuration, I have to specify a flake each time I run nix develop, which means either fetching from github each time, or having a local copy of my motherflake cloned somewhere in my home (eeeeh). Is there a way to have that behavior?

In some sense, what I want is for a given machine to not just have the appropriate nixosconfiguration built and deployed, but instead for it to have knowledge of the whole motherflake, but I don’t know if this idea is a good one. Any thoughts?

Another question: it also seems that nix develop is not so much creating a “dev environment”, but something suitable to automatically run build/install commands as part of an automated process. I want my usual shell in here, with all its bells and whistle, when I’m developping something. Is nix develop suited for this use case?

Cheers,

Hey long time no see,

I am not sure to understand what you want to do here.

Do you know that you can have multiple devshells in a single flake (devShells.<name>) ? Combining that with using the registry to not have to type the full path to the flake should allow you to have commands like nix develop shells#clang or nix develop shells#haskell.

There is also another way but it is very much a hack, you could do something like this

{ pkgs, ... }:
let
  devshell1 = pkgs.mkShell {
    buildInputs = [ pkgs.gcc ];
  };
in
{
  environment.systemPackages = [
    (pkgs.writeScriptBin "devshell1" ''${pkgs.bash} --init-file ${devshell1}'' )
  ];
}

which would give you a global script to drop into a bash shell loaded with the tools you want. The downside is that mkShell will replace your environment variables.

For the last question, the whole machinery under the hood is highly tied to bash so switching to another shell would probably break things but nix develop has a -c option that can start your preferred shell after bash set all up. It would look like nix develop -c zsh shells#clang nothing that a little aliasing cannot fix.

Funnily, it seems that the -c option and the devShells without default is broken at the moment.

2 Likes

Uh, it is not broken but the flake ‘uri’ has to be put before the -c option.

Hm, the way that I have set up my different dev environments is that I have a master flake (not so sure if I like this monolith approach yet), which looks something like

$ cat ~/src/nixfiles/masterflake.nix
{
  inputs = {
    nixpkgs.url = ...;
    mono-latest.url = ...;
    nixpkgs-2015.url = ...;
  };
};
outputs = { ... }:
in rec {
  devShells.${system} = {
    "project1" = nixpkgs.mkShell { ... };
    "project2" = mono-latest.mkShell { ... };
  };
};

and then I use direnv in the root folder of each project, like this:

$ cat project1/.direnv
use flake ~/src/nixfiles/masterflake.nix#project1

this setup serves me quite well, allowing me to keep environments somewhat in sync, but also update flake inputs independently, if needed for shaky environments.

2 Likes

I am not sure about best practices byt I have tinny script that provides me some generic dev environments and then I have environments in my projects.

The script as a package can be seen here https://github.com/Cynerd/nixos-personal/blob/8e6e3d387a6f9f622f1d84c444924d61069f7af3/pkgs/dev/default.nix

The speciality there is that I include output path in it for my dev shells to ensure that they are present in the store. The primary reason is because I need some cross compilers that take considerable time to build and thus I do not want them to be removed from the store when I can use them (they are removed when old dev script is collected).

The way I pass those dev shells to the package is not nice at all. My flake is in some places a lot hacky but it can give you an idea of how you can have dev environments as part of the nixos system.

The common usage then is for example: dev c and then dev .. The first dev is to get my tools (such as clangd) and the second is to pull in project’s dependencies.

2 Likes

Heyo, sorry for the long delay before the response!

Thank you all so much for your insights, I hadn’t thought of using the flake registry to register a “home” registry for all my devshells, while not entirely “local” it beats referencing the url or a local folder, and should be good enough for all my “basic” devshells!

I also stumbled on many high level wrappers around mkshell, notably https://devenv.sh/ which should simplify the work.

Now I just need to bother people with a new thread regarding some home-manager questions, and with any luck I’ll have a decent enough setup to finally replace my workstation!

See also Support defining devenvs outside the repository tree · Issue #67 · cachix/devenv · GitHub and leave a thumbs up :slight_smile: