From NixOS Wiki
Jump to: navigation, search

The Python packages available to the interpreter must be declared when installing Python.

To install, say Python 3 with pandas and requests, define a new package python-with-my-packages:

with pkgs;
  my-python-packages = python-packages: with python-packages; [
    # other python packages you want
  python-with-my-packages = python3.withPackages my-python-packages;
in ...

You can put python-with-my-packages into your environment.systemPackages for a system-wide installation, for instance. Be mindful that pythonX.withPackages creates a pythonX-Y.Z.W-env package which is read only, so you can't use pip to install packages in, say, a virtual environment (as described below). Put python in your configuration.nix if you want to use the solution as described in the section "Python Virtual Environment".

There are several versions of Python available. Replace python3 with python2 or pypy in the above snippet according to your needs.

Explanation (optional)

We defined a function my-python-packages which takes as input a set python-packages and returns a list of attributes thereof.

Development shell

withPackages env

If you need only python:

# shell.nix
{ pkgs ? import <nixpkgs> {} }:
  python-with-my-packages = pkgs.python3.withPackages (p: with p; [
    # other python packages you want
python-with-my-packages.env # replacement for pkgs.mkShell


If you need python and other dependencies:

# shell.nix
{ pkgs ? import <nixpkgs> {} }:
  my-python = pkgs.python3;
  python-with-my-packages = my-python.withPackages (p: with p; [
    # other python packages you want
pkgs.mkShell {
  buildInputs = [
    # other dependencies
  shellHook = ''
    # maybe set more env-vars

Using alternative packages

We saw above how to install Python packages using nixpkgs. Since these are written by hand by nixpkgs maintainers, it isn't uncommon for packages you want to be missing or out of date. To create a custom Python environment with your own package(s), first create a derivation for each python package (look at examples in the python-modules subfolder in Nixpkgs). Then, use those derivations with callPackage as follows:

with pkgs;
  my-python-package = ps: ps.callPackage ./my-package.nix {};
  python-with-my-packages = python3.withPackages(ps: with ps; [
    (my-python-package ps)
in ...

Package and development shell for a python project

It is possible to use buildPythonApplication to package python applications. As explained in the nixpkgs manual, it uses the widely used `` file in order to package properly the application. We now show how to package a simple python application: a basic flask web server.

First, we write the python code, say in a file Here we create a basic flask web server;

#!/usr/bin/env python

from flask import Flask
app = Flask(__name__)

def hello_world():
    return 'Hello, World!'

if __name__ == '__main__':"", port=8080)

Then, we create the file, which basically explains which are the executables:

#!/usr/bin/env python

from setuptools import setup, find_packages

      # Modules to import from other scripts:
      # Executables

Finally, our nix derivation is now trivial: the file derivation.nix just needs to provide the python packages (here flask):

{ lib, python3Packages }:
with python3Packages;
buildPythonApplication {
  pname = "demo-flask-vuejs-rest";
  version = "1.0";

  propagatedBuildInputs = [ flask ];

  src = ./.;

and we can now load this derivation from our file default.nix:

{ pkgs ? import <nixpkgs> {} }:
pkgs.callPackage ./derivation.nix {}

We can now build with:

$ nix-build
$ ./result/bin/ 
 * Serving Flask app ".web_interface" (lazy loading)

or just enter a nix-shell, and directly execute your program or python if it's easier to develop:

$ nix-shell
[nix-shell]$ chmod +x
[nix-shell]$ ./ 
 * Serving Flask app "web_interface" (lazy loading)

[nix-shell]$ python
Python 3.8.7 (default, Dec 21 2020, 17:18:55) 
[GCC 10.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import flask

Python virtual environment

Starting from Python 3 virtual environment is natively supported. The Python 3 venv approach has the benefit of forcing you to choose a specific version of the Python 3 interpreter that should be used to create the virtual environment. This avoids any confusion as to which Python installation the new environment is based on.

Recommended usage:

  • Python 3.3-3.4 (old): the recommended way to create a virtual environment was to use the pyvenv command-line tool that also comes included with your Python 3 installation by default.
  • Python 3.6+: python3 -m venv is the way to go.

Put your packages in a requirements.txt:


Then setup the virtualenv:

python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

Installing packages with pip that need to compile code or use C libraries will sometimes fail due to not finding dependencies in the expected places. In that case you can use buildFHSUserEnv to make yourself a sandbox that appears like a more typical Linux install. For example if you were working with machine learning code you could use:

{ pkgs ? import <nixpkgs> {} }:
(pkgs.buildFHSUserEnv {
  name = "pipzone";
  targetPkgs = pkgs: (with pkgs; [
  runScript = "bash";

In pip-shell.nix, and enter the environment with:

nix-shell pip-shell.nix
virtualenv venv
source venv/bin/activate

Emulating virtualenv with nix-shell

In some cases virtualenv fails to install a library because it requires patching on NixOS (example 1, example 2, general issue). In this cases it is better to replace those libraries with ones from Nix.

Let's say, that nanomsg library fails to install in virtualenv. Then write a shell.nix file:

  pkgs = import <nixpkgs> {};
  nanomsg-py = expression for this python library...;
in pkgs.mkShell {
  buildInputs = [
  shellHook = ''
    # Tells pip to put packages into $PIP_PREFIX instead of the usual locations.
    # See
    export PIP_PREFIX=$(pwd)/_build/pip_packages
    export PYTHONPATH="$PIP_PREFIX/${pkgs.python3.sitePackages}:$PYTHONPATH"
    export PATH="$PIP_PREFIX/bin:$PATH"

After entering the environment with `nix-shell`, you can install new python libraries with dump `pip install`, but nanomsg will be detected as installed.

Discussion and consequences of this approach are in PR


Install the package nix-env -if -A mach-nix or pip install git+git:// and run

mach-nix env ./env -r requirements.txt
# This will generate the python environment into ./env. To activate it, execute:
nix-shell ./env


# nix.extraOptions = ''  experimental-features = nix-command flakes    '';
nix-shell -p nixFlakes --run "nix run github:davhau/mach-nix#with.ipython.geopandas --show-trace "

cmd-line tool:

  mach-nix = import (builtins.fetchGit {
    url = "";
    ref = "refs/tags/3.1.1";
  }) {};
mach-nix.mkPython {
  requirements = ''

Please have a look at more examples.


Install the micromamba package (currently in nixpkgs-unstable only). You can create environments and install packages as documented by micromamba e.g.

micromamba create -n my-environment python=3.7 numpy=1.21.0 -c conda-forge

To activate an environment you will need a FHS environment e.g.:

$ nix-shell -E 'with import <nixpkgs> {}; (pkgs.buildFHSUserEnv { name = "fhs"; }).env'
$ eval "$(micromamba shell hook -s bash)"
$ micromamba activate my-environment
$ python
>>> import numpy as np

Eventually you'll probably want to put this in a shell.nix so you won't have to type all that stuff every time e.g.:

  pkgs = import (fetchTarball "") {};

  fhs = pkgs.buildFHSUserEnv {
    name = "my-fhs-environment";

    targetPkgs = _: [

    profile = ''
      set -e
      eval "$(micromamba shell hook -s bash)"
      export MAMBA_ROOT_PREFIX=${builtins.getEnv "PWD"}/.mamba
      micromamba create -q -n my-mamba-environment
      micromamba activate my-mamba-environment
      micromamba install --yes -f conda-requirements.txt -c conda-forge
      set +e
in fhs.env


Install the package conda and run

conda env update --file environment.yml

Imperative use

It is also possible to use conda-install directly. On first use, run


to set up conda in ~/.conda


pip2nix generate nix expressions for Python packages.

Also see the pypi2nix-project (abandoned in 2019).

Contribution guidelines


According to the official guidelines for python new package expressions for libraries should be placed in pkgs/development/python-modules/<name>/default.nix. Those expressions are then referenced from pkgs/top-level/python-packages.nix like in this example:

  aenum = callPackage ../development/python-modules/aenum { };

The reasoning behind this is the large size of pkgs/top-level/python-packages.nix.


Python applications instead should be referenced directly from pkgs/top-level/all-packages.nix.

The expression should take pythonPackages as one of the arguments, which guarantees that packages belong to the same set. For example:

{ lib
, pythonPackages

with pythonPackages;

buildPythonApplication rec {
# ...

Special Modules


gobject-introspection based python modules need some environment variables to work correctly. For standalone applications, wrapGAppsHook (see the relevant documentation) wraps the executable with the necessary variables. But this is not fit for development. In this case use a nix-shell with gobject-introspection and all the libraries you are using (gtk and so on) as buildInputs. For example:

$ nix-shell -p gobjectIntrospection gtk3 'python2.withPackages (ps: with ps; [ pygobject3 ])' --run "python -c \"import pygtkcompat; pygtkcompat.enable_gtk(version='3.0')\""

Or, if you want to use matplotlib interactively:

$ nix-shell -p gobjectIntrospection gtk3 'python36.withPackages(ps : with ps; [ matplotlib pygobject3 ipython ])'
$ ipython
In [1]: import matplotlib
In [2]: matplotlib.use('gtk3agg')
In [3]: import matplotlib.pyplot as plt
In [4]: plt.ion()
In [5]: plt.plot([1,3,2,4])

You can also set backend : GTK3Agg in your ~/.config/matplotlib/matplotlibrc file to avoid having to call matplotlib.use('gtk3agg').

See also