When developing and running software, and many times, you need a very particular set of libraries in your environment. You achieve this with virtual environments, containers, and other tricks. However, you do not necessarily need all that. One common case is when you program in Python, you must choose between the two big versions. This has caused many headaches for users and developers alike. You can avoid all this if your libraries are designated, especially for one run. This may sound impossible or unnecessary, but it is very convenient for rare use cases and development.

Revision Hell

Anyone who reads this will be familiar with the Python issue of using a different version of the language. That is just one glaring example where even users are affected. This is due to old brilliant projects that have stopped maintaining the software. In many other situations, you also need great control over what is running and what libraries are available. Programming in C and C uses libraries that often need to be the exact version when you compile. Otherwise, you will be re-writing parts of the software you never intended to touch. Many developers use a container with all the libraries, and all other works happen on the host computer.

The Nix Fix

How does nix take care of this problem? Well, they have all the files in a store with hashes to identify the exact version. The environment you are going to use, then link to the library or execute, is something you would want to use for your current situation. For a running system, you can then use many versions of an application and even libraries. When you want to develop, you create a configuration file that covers the needs of your current project.

Configuration Files

When you have NixOS installed, the configuration.nix will control your environment for the whole computer. With that said, you can control it in every instance of your shell. Irrespective if you have NixOS or run any other distribution, you can use another nix file. The file is called default.nix by default. You can use this to make a directory structure that has a particular environment. The workflow is to create the default nix file to reflect what you want your environment to support. Then change the directory and run nix-build, followed by running the nix-shell. You can also use any name for the file if you specify it on the command line.

$ cd MyProject/


$ nix-build # Once, when you have changed something.


$ nix-shell default.nix

The parameter for the nix-shell will be implied, but if you want to have several in one directory, then you can use the switch. With the correct values set, you now have your environment the same every time you start nix-shell. If you move the nix file, you will be able to get the same anywhere! The big issue becomes; what do I put in the nix files?

The files use the Nix expression language, it is almost a programming language.

A few examples

Below, there are a few examples that can help you. There are many more things you can do to tweak your environment. This is a long exciting journey, but it will probably slow you down from the beginning. Before you get there, use other people’s code. This list is short, so look for ideas across the web.

Python

When you want to create a Python project, you would normally use virtual environments. With Nix, this is not necessary. Instead, you can create a shell.nix file that declares which version you want. The simplest way to do this is to use python38Full.

{ pkgs ? import <nixpkgs> {} }:


pkgs.mkShell {


    # nativeBuildInputs is usually what you want — tools you need to run


    nativeBuildInputs = [ pkgs.buildPackages.python38Full];

}

This compiles an environment with all parts of the Python 3.8 that comes with NixOS. If you want to minimize your environment, you can choose its particular parts. You can also add your source code remotely with fetch functions.

Python Flask

An example of web development is a flask. It is a very powerful package for making web pages, even really complex ones, without much effort. Since Flask is a popular framework, there is a ready NixOS package for it. The file to control the build for this is called default.nix.

{ pkgs ? import <nixpkgs> {} }:

pkgs.python38Packages.buildPythonApplication {


    pname = “NixApp”;


    src = ./.;


    version = “0.1”;


    propagatedBuildInputs = [ pkgs.python38Packages.flask ];

}

As you can see, there are packages from nixpkgs that cover flask. If you want to use something else, you add them inside the square brackets. This goes for all types of packages that are included in the NixPkgs repository. If the package does not exist, use a fetcher.

Python Development

If you want to start a Python development environment, you add packages you need according to revision and others.

with import <nixpkgs> {};

with pkgs.python37Packages;

stdenv.mkDerivation {


    name = “python-devel”;


    req = ./requirements.txt;


    builder = “${bash}/bin/bash”;


    setup = ./setup_venv.sh;


    buildInputs = [


        python37Full


        python37Packages.pip


    ];


    system = builtins.currentSystem;


    shellHook =


    SOURCE_DATE_EPOCH=$(date %s)


    ;

}

In the shellHook, between the double apostrophes (”), you can put any scripts you like. Again, think about what might already exist, as there are many smart people out there that are already developing using NixOS.

JavaScript

The standard version to use JavaScript, or more precisely, nodejs, is the nix script below. Name it shell.nix and place it in your project directory, then start with the nix-shell command.

with import <nixpkgs> {};

stdenv.mkDerivation {


    name = “node”;


    buildInputs = [


    nodejs


    ];


    shellHook =


        export PATH=“$PWD/node_modules/.bin/:$PATH”


    ;

}

This is the simplest, possible trick, although there are much more available. You can see how to add a script that you would otherwise run manually. Use this carefully and look for full alternatives before you do this.

Jupyter

The script below initializes a directory to host a batch of functions where you can run Jupyter. The other packages are for statistics and machine learning. You can also remove and add according to your needs.

with import {};

(


let


    in python38.withPackages (ps: with ps; [ geopandas ipython jupyter


    jupyterlab matplotlib numpy pandas seaborn toolz ])


).env

Configurations

For your IDE, editor, or anything, really, you can also bake in your settings. For developers, vim and Emacs will be the first candidates for this specialization. Vim has its own set of plugins available as nixpkgs.

Fetchers

The basis of the packages in NixOS are files that point to sources and what is needed for compiling the packages. You can use this if you are missing a package. As long as you can find the source package, you can use a fetcher to install it. The standard fetcher fetches tarballs but is named fetchurl.

{ stdenv, fetchurl }:

stdenv.mkDerivation {


    name = “hello”;


    src = fetchurl {


        url = “http://www.example.org/hello.tar.gz”;


        sha256 = “1111111111111111111111111111111111111111111111111111”;


    };


}

You can use it the way it is in the above code. You also have fetchgit and other version control systems. On top of this, the major git services are covered with fetchFromGitHub, fetchFromGitLab, and more. With all these fetchers, you should be able to find any package you want for NixOS.

Conclusion

Using NixOS requires a bit more effort than other distributions. Having said that, if you want to develop software, the effort is worth it. You will keep your main system cleaner and can hop between projects without creating troublesome conflicts between environments.

About the author

<img alt="Mats Tage Axelsson" data-lazy-src="https://kirelos.com/wp-content/uploads/2021/01/echo/Matstage_Low-150×150.jpg5ff5f944beb3c.jpg" height="112" src="data:image/svg xml,” width=”112″>

Mats Tage Axelsson

I am a freelance writer for Linux magazines. I enjoy finding out what is possible under Linux and how we can all chip in to improve it. I also cover renewable energy and the new way the grid operates. You can find more of my writing on my blog.