Some generic questions about using Nix for development environments

Hi all,

my goal is to use nix tools to be able to create development environments for me and my collegues.
We are an agency, which means many projects with different requirements.
Some projects needs old versions of tools, and this seems the bread and butter of nix.
We are using asdf but you know how limited it is compared to nix.

Now the questions:

  1. Can we have development environments with just nix on our OSes, or do we need to switch to NixOS?
  2. To create development environment, which tool should I look into? nix-env or nix-shell?
  3. I have found this page on the wiki, do you believe it is up to date with current best practices? Development environment with nix-shell - NixOS Wiki
  4. It’s really unclear to me which role flakes have in this topic. Are they recommended or just an option based on personal taste?

Thank you
Cheers!

  1. You can run Nix on any Linux distro, but if you might have to take additional steps if you need e.g. OpenGL to run/test the apps.
    2./3. nix-shell to load project-specific shell.nix (nix-env would install things and break your separation of projects)
  2. Flakes offer additional benefits, such as better reproducibility (for nix-shell you would need extra tools, such as niv), but have their own quirks as flakes have not been finally standardized. For my personal projects I switched to Flakes and nix develop from nix-shell and niv, but conversion in either direction is not too hard. Also have a look at https://devenv.sh/

Depending on the type

Ok, I’ll start with nix on existing OSes

Got it, thanks.

Would you personally recommend start with nix-shell and niv and then move to flakes, or jump right into flakes?

Will do, but first I want to get comfortable with the basics

Thank you

Personal Opinion:

  1. Use the installer from Determinate Systems to get a flake-enabled nix installation on the Linux distro of your preference
  2. Jump right into flakes. ( + direnv)
2 Likes

Hello and welcome!

  1. Can we have development environments with just nix on our OSes, or do we need to switch to NixOS?

No, you can use any Linux distribution. I would recommend installing Nix on an existing OS with the Determinate Systems installer, which is what has worked best for me. Although it’s possible to use a non-Linux OS like macOS, I would be hesitant to suggest this if you’re starting out with Nix.

  1. To create development environment, which tool should I look into? nix-env or nix-shell?

Use nix-shell for your use-case; nix-env is more for when you want to use Nix like an ordinary Linux distribution with only one version of a package installed at a time. Flakes is a good idea for the kind of thing you’re doing; I’ll get to that below.

  1. I have found this page on the wiki, do you believe it is up to date with current best practices? Development environment with nix-shell - NixOS Wiki

Yes, this is still correct.

  1. It’s really unclear to me which role flakes have in this topic. Are they recommended or just an option based on personal taste?

Flakes are an experimental feature in Nix. They are really powerful for lots of things, and they are what I personally would recommend you use. Despite being experimental, they rarely (if ever) cause problems now; in fact, just a few days ago an official plan for promoting them to a core feature was accepted.

Here’s my suggestion: read Nix from First Principles: Flake Edition, and try out all the examples. Ignore the installation chapter of this, and just use the Determinate Systems installer I mentioned earlier instead. It will take you a few hours to read all the chapters and run the examples, and by the end you will know almost everything you will ever need for your use case!

Feel free to post on this thread or make a new one if you get stuck. :slight_smile:

I replied before noticing @wamserma’s post; clearly we both share the same feelings about the topic :smiley:

Thank you @seabass for the clear answer.

In our use case, we are thinking about nix-shell to replace asdf.
We use erlang.
In asdf we can specify the exact erlang version we need in the project. For example, erlang 24.3.4.8 (https://www.erlang.org/patches/otp-24.3.4.8)

We can pin the exact minor version with both asdf and docker.

IIUC we can’t do that with nix-shell, as we have to stick with the version from nixpkgs (which is erlang 24.3.4.11).
The other option would be to write our own derivation to get the exact minor version we need, is that correct?

If that is correct, it seems really a lot more work to achieve the same result. So I wonder what could be the reason for us to use nix:thinking:

Cheers!

Why do you want to control the very exact version of the Erlang runtime while ignoring to manage its dependencies at all?

In my experience the circumstances in which it really matters wether you have a x.y.z.1 or a x.y.z.2 of the runtime are rare.

Anyway if the exact version indeed matters, there are projects in the wild that allow for a more fine grained control of the runtime version.

For Erlang (and some other BEAMtech) there is @shanesveller nix-beam-flakes.

I never checked the implementation or what it provides. So far I went well with just selecting OTP by major release and Elixir by minor from nixpkgs.

I never had any troubles with this, neither in job, nor hobby.

We don’t want to have any kind of surprise (and we do that with other tools as well, mainly elixir and node).
Problem I see is that if we stick with nixos packages, it’s only x of x.y.z.2 which seems a bit dangerous.

flakes keep popping up, I really believe we have to start with them. Thank you.

Glad to hear that, unfortunately all the erlang projects we have in production are using asdf (or kerl) and we have the minor pinned. So I can’t be sure we will not have issues with a more relaxed approach.

I’ll take your experience into account though!

Cheers!

The problem is probably that you are not pinning, but rely on some random nix path/channel state.

If you have properly pinned shells and drvs, be it using flakes, npins, niv or whatever. You can’t only say in advance which OTP version will be used, but also exactly which version of wx, libz, SSL and others!

In short: properly pinned nixpkgs has much less surprises than a 10 line .tool-versions.

1 Like

Yeah we have old erlang projects that needs openssl 1.x that would benefit from nix-shell.
asdf simply can’t handle that.

I’ll start reading Nix from First Principles: Flake Edition - Tony Finn
Seems well done.

Cheers!

@NobbZ thanks for the mention! :beers:

@carlotm Regarding my flake library, if you do wind up taking a look please do let me know if the unmerged PR/branch for README + Docs needs additional work for folks who are not yet acclimated to using flakes. That sort of critical feedback is super welcome.

I daily drive that library every day for personal/professional Elixir work and a (small) part of the motive was specifically to let people offboard from asdf. I find the asdf experience disappointing on MacOS, largely due to the inherent weaknesses of homebrew, plus every dev needing to rebuild the runtime on each of their machines. Nix binary caching can more or less eliminate that concern if you’re already bought in on using Nix as an org-level approach.

I do provide caching of the latest ~3 Elixir x Erlang for Intel Macs, but ARM arch is not yet supported by the managed GitHub Actions runners.

For my large project (embedded OS) I’m using the nixpkgs repo pinned to a specific rev with modifications for versions, different defaults, etc. I have all that packaged in a “nixpkgs.nix” file which is referenced by “shell.nix” for a dev environment and “default.nix” for production builds. Once in a while I update the pinned rev and then everything updates at once.

I like this scheme because it is simple, explicit, and highly reproducible. I did have some “niv” usage at various locations in the project, but they caused headaches at update time. The system got simpler and more robust when I removed niv and leaned into the top level nixpkgs pin. I am skeptical that flakes have anything to offer for this scenario, but I will take a good look at them when they are released.

Works for me, I had to compile Apache Modules that only works with Apache of 2.2.22

{
  description = "Dev Environment";

  inputs.dsf.url     = "github:cruel-intentions/devshell-files";
  inputs.nixpkgs.url = "github:nixos/nixpkgs/release-23.05";
  inputs.nixolds.url = "github:nixos/nixpkgs/0.14";
  inputs.nixolds.flake = false;
  inputs.dsf.inputs.nixpkgs.follows = "nixpkgs";

  outputs = inputs:
    inputs.dsf.lib.shell inputs [
      # my devShell config using nixolds and nixpkgs
      ./project.nix 
    ] //
    { # my package using nixolds
      packages.x86_64-linux.default = inputs.nixpkgs.legacyPackages.x86_64-linux.callPackage ./default.nix {
        pkgsold =  import inputs.nixolds {
          system = "x86_64-linux";
        };
      };
    };
}

default.nix

{
  pkgs         ? import <nixpkgs>,
  pkgsold      ? pkgs,
}:
let
  apacheHttpd  = pkgsold.apacheHttpd;
  libxml2      = pkgsold.libxml2;
  openssl      = pkgsold.openssl;
  pkg-config   = pkgsold.pkgconfig;
  sasl         = pkgsold.cyrus_sasl;
in
pkgsold.stdenv.mkDerivation {
}

try
NixHub to find old versions or Marcelo Tool

1 Like