Skip to content

Python

With devenv, you get a ready-to-use Python environment — complete with the version you need, a virtual environment, and your preferred package manager. This guide walks you through everything from basic setup to advanced topics like native libraries and Nix-packaged dependencies.

Getting started

To add Python to your project, enable it in your devenv.nix:

{
  languages.python.enable = true;
}

This gives you python3 and pip in your shell, using the version of Python that ships with your nixpkgs input.

Choosing a Python version

To use a specific Python version, set the version option:

{
  languages.python = {
    enable = true;
    version = "3.11";
  };
}

You can use a major.minor version like "3.11", or pin an exact release like "3.11.3".

Under the hood, this pulls the Python build from nixpkgs-python, which needs to be added as an input in your devenv.yaml:

inputs:
  nixpkgs-python:
    url: github:cachix/nixpkgs-python
    inputs:
      nixpkgs:
        follows: nixpkgs

If you don't need a specific version, you can skip this — devenv uses the default Python 3 from nixpkgs.

Virtual environments

Python projects typically use virtual environments to isolate dependencies. devenv can create and manage one for you:

{
  languages.python = {
    enable = true;
    venv.enable = true;
  };
}

The virtual environment is stored in $DEVENV_STATE/venv and is activated automatically every time you enter the shell. If the Python interpreter changes (for example, after updating version), the virtual environment is recreated.

Installing packages from requirements

If your project uses a requirements file, you can point devenv to it. Packages are installed with pip when the shell starts:

{
  languages.python = {
    enable = true;
    venv = {
      enable = true;
      requirements = ./requirements.txt;
      # Or write requirements inline:
      # requirements = ''
      #   requests
      #   flask>=3.0
      # '';
    };
  };
}

devenv tracks a checksum of your requirements and your Python interpreter, so packages are only reinstalled when something actually changes.

Set venv.quiet = true to suppress pip output during installation.

Changing the project directory

If your Python code lives in a subdirectory rather than the project root, set the directory option:

{
  languages.python = {
    enable = true;
    directory = "./backend";
    venv.enable = true;
  };
}

This changes where devenv looks for files like pyproject.toml, requirements.txt, and poetry.lock. It also affects where the virtual environment is initialized. The path can be absolute or relative to the root of the devenv project.

Package managers

devenv integrates with Python package managers to automatically install dependencies when you enter the shell.

Poetry and uv are mutually exclusive

You cannot enable both poetry.install and uv.sync at the same time.

uv

uv is a fast Python package manager that uses pyproject.toml to manage dependencies. devenv can run uv sync automatically when you enter the shell:

{
  languages.python = {
    enable = true;
    venv.enable = true;
    uv = {
      enable = true;
      sync.enable = true;
    };
  };
}

This expects a pyproject.toml in your project directory (or the directory set by languages.python.directory). devenv ensures uv uses the Python interpreter from your configuration rather than downloading its own.

Dependency groups and extras

You can control exactly which dependency groups and extras uv installs:

{
  languages.python = {
    enable = true;
    venv.enable = true;
    uv = {
      enable = true;
      sync = {
        enable = true;
        allGroups = true;             # Install all dependency groups
        # groups = [ "dev" "test" ];  # Or pick specific ones
        # extras = [ "plotting" ];    # Specific extras
        # allExtras = true;           # All extras
      };
    };
  };
}

For uv workspaces and additional sync flags, see the options reference below.

Poetry

Poetry manages Python project dependencies and packaging. devenv can run poetry install and activate the virtual environment for you:

{
  languages.python = {
    enable = true;
    poetry = {
      enable = true;
      install.enable = true;
      activate.enable = true;
    };
  };
}

This expects pyproject.toml and poetry.lock in your project directory. Poetry creates its virtual environment in .venv inside your project directory (rather than $DEVENV_STATE/venv).

Install options

You can fine-tune what Poetry installs:

{
  languages.python = {
    enable = true;
    poetry = {
      enable = true;
      install = {
        enable = true;
        installRootPackage = true;    # Install your project itself
        groups = [ "dev" "test" ];    # Specific dependency groups
        # ignoredGroups = [ "docs" ]; # Groups to skip
        # allExtras = true;           # All extras
        quiet = true;                 # Suppress output
      };
      activate.enable = true;
    };
  };
}

See the options reference below for the full set of install options.

Using Nix Python packages

Nix can build and cache Python packages, so you don't need to compile them from source or download them from PyPI. This is especially useful for packages that are difficult to install with pip — like tkinter, or packages with complex native dependencies.

Use withPackages to bundle Nix-built packages into your Python interpreter:

{
  languages.python = {
    enable = true;
    package = pkgs.python3.withPackages (ps: [
      ps.numpy
      ps.tkinter
    ]);
    venv.enable = true;
  };
}

You can combine this with uv or Poetry — the Nix packages provide a base, and your package manager handles the rest. When a virtual environment is active, packages installed by pip/uv/Poetry take priority over the Nix-provided ones.

Native libraries

Some Python packages — like Pillow, grpcio, or transformers — link against native C/C++ libraries at build time. In a Nix-based environment, these libraries aren't in the usual system locations, so pip may fail to find them.

To fix this, add the native libraries to packages:

{
  packages = [ pkgs.cairo pkgs.zlib ];

  languages.python = {
    enable = true;
    venv.enable = true;
    venv.requirements = ''
      pillow
      grpcio-tools
    '';
  };
}

devenv adds these libraries to LD_LIBRARY_PATH (Linux) or DYLD_LIBRARY_PATH (macOS), and includes the C runtime library automatically.

For more control over library search paths, use the libraries option.

Manylinux support

On Linux, some pre-built Python wheels depend on manylinux compatibility libraries. If you run into related installation errors, enable manylinux support:

{
  languages.python.manylinux.enable = true;
}

Building Python projects with Nix

You can turn your Python project into a reproducible Nix build using uv2nix. This is useful for creating deployable artifacts or integrating with other Nix-based infrastructure:

{ config, ... }:

let
  myapp = config.languages.python.import ./path/to/project {};
in
{
  languages.python.enable = true;
  packages = [ myapp ];
  outputs = { inherit myapp; };
}

The project directory must contain a pyproject.toml. The package name is inferred automatically, or you can set it explicitly with { packageName = "my-custom-name"; }.

Language server

devenv includes Pyright as the default Python language server, enabled automatically.

To use a different language server, or disable it entirely:

{
  languages.python = {
    enable = true;
    # Use a different LSP:
    lsp.package = pkgs.python3Packages.python-lsp-server;
    # Or disable it entirely:
    # lsp.enable = false;
  };
}

Putting it all together

Here's a complete example of a Django project using Poetry, with a PostgreSQL database and a dev server managed by devenv:

{ config, pkgs, ... }:

let
  db_user = "postgres";
  db_name = "myapp";
in
{
  languages.python = {
    enable = true;
    version = "3.11";
    poetry = {
      enable = true;
      install.enable = true;
      activate.enable = true;
    };
  };

  env = {
    DATABASE_URL = "postgres://${db_user}@/${db_name}?host=${config.env.PGHOST}";
    SECRET_KEY = "dev-only-secret"; # Do not use in production
  };

  services.postgres = {
    enable = true;
    initialDatabases = [{ name = db_name; user = db_user; }];
  };

  processes.runserver = {
    exec = "exec python manage.py runserver";
    after = [ "devenv:processes:postgres" ];
  };
}

Options

languages.python.enable

Whether to enable tools for Python development.

Type: boolean

Default:

false

Example:

true

Declared by: - https://github.com/cachix/devenv/blob/main/src/modules/languages/python

languages.python.package

The Python package to use.

Type: package

Default:

pkgs.python3

Declared by: - https://github.com/cachix/devenv/blob/main/src/modules/languages/python

languages.python.directory

The Python project’s root directory. Defaults to the root of the devenv project. Can be an absolute path or one relative to the root of the devenv project.

Type: string

Default:

config.devenv.root

Example:

"./directory"

Declared by: - https://github.com/cachix/devenv/blob/main/src/modules/languages/python

languages.python.import

Import a Python project using uv2nix.

This function takes a path to a directory containing a pyproject.toml file and returns a derivation that builds the Python project using uv2nix.

Example usage:

let
  mypackage = config.languages.python.import ./path/to/python/project {};
in {
  languages.python.enable = true;
  packages = [ mypackage ];
}

Type: function that evaluates to a(n) function that evaluates to a(n) package

Declared by: - https://github.com/cachix/devenv/blob/main/src/modules/languages/python

languages.python.libraries

Additional libraries to make available to the Python interpreter.

This is useful when you want to use Python wheels that depend on native libraries.

Type: list of absolute path

Default:

[ "${config.devenv.dotfile}/profile" ]

Declared by: - https://github.com/cachix/devenv/blob/main/src/modules/languages/python

languages.python.lsp.enable

Whether to enable Python Language Server.

Type: boolean

Default:

true

Example:

true

Declared by: - https://github.com/cachix/devenv/blob/main/src/modules/languages/python

languages.python.lsp.package

The Python language server package to use.

Type: package

Default:

pkgs.pyright

Declared by: - https://github.com/cachix/devenv/blob/main/src/modules/languages/python

languages.python.manylinux.enable

Whether to install manylinux2014 libraries.

Enabled by default on linux;

This is useful when you want to use Python wheels that depend on manylinux2014 libraries.

Type: boolean

Default:

false

Declared by: - https://github.com/cachix/devenv/blob/main/src/modules/languages/python

languages.python.patches.buildEnv.enable

Whether to apply fixes to Python’s buildEnv for correct runtime initialization:

  • Executables use --inherit-argv0 and --resolve-argv0 to ensure Python initializes with correct sys.prefix and sys.base_prefix
  • Python package scripts are unwrapped to invoke the environment’s interpreter directly

Without these fixes, Python may not initialize with the correct prefix paths.

Enabled by default. Newer nixpkgs releases may include upstream fixes that make this patch obsolete.

Type: boolean

Default:

true

Declared by: - https://github.com/cachix/devenv/blob/main/src/modules/languages/python

languages.python.poetry.enable

Whether to enable poetry.

Type: boolean

Default:

false

Example:

true

Declared by: - https://github.com/cachix/devenv/blob/main/src/modules/languages/python

languages.python.poetry.package

The Poetry package to use.

Type: package

Default:

pkgs.poetry

Declared by: - https://github.com/cachix/devenv/blob/main/src/modules/languages/python

languages.python.poetry.activate.enable

Whether to activate the poetry virtual environment automatically.

Type: boolean

Default:

false

Declared by: - https://github.com/cachix/devenv/blob/main/src/modules/languages/python

languages.python.poetry.install.enable

Whether to enable poetry install during devenv initialisation.

Type: boolean

Default:

false

Example:

true

Declared by: - https://github.com/cachix/devenv/blob/main/src/modules/languages/python

languages.python.poetry.install.allExtras

Whether to install all extras. See --all-extras.

Type: boolean

Default:

false

Declared by: - https://github.com/cachix/devenv/blob/main/src/modules/languages/python

languages.python.poetry.install.allGroups

Whether to install all groups. See --all-groups.

Type: boolean

Default:

false

Declared by: - https://github.com/cachix/devenv/blob/main/src/modules/languages/python

languages.python.poetry.install.compile

Whether poetry install should compile Python source files to bytecode.

Type: boolean

Default:

false

Declared by: - https://github.com/cachix/devenv/blob/main/src/modules/languages/python

languages.python.poetry.install.extras

Which extras to install. See --extras.

Type: list of string

Default:

[ ]

Declared by: - https://github.com/cachix/devenv/blob/main/src/modules/languages/python

languages.python.poetry.install.groups

Which dependency groups to install. See --with.

Type: list of string

Default:

[ ]

Declared by: - https://github.com/cachix/devenv/blob/main/src/modules/languages/python

languages.python.poetry.install.ignoredGroups

Which dependency groups to ignore. See --without.

Type: list of string

Default:

[ ]

Declared by: - https://github.com/cachix/devenv/blob/main/src/modules/languages/python

languages.python.poetry.install.installRootPackage

Whether the root package (your project) should be installed. See --no-root

Type: boolean

Default:

false

Declared by: - https://github.com/cachix/devenv/blob/main/src/modules/languages/python

languages.python.poetry.install.onlyGroups

Which dependency groups to exclusively install. See --only.

Type: list of string

Default:

[ ]

Declared by: - https://github.com/cachix/devenv/blob/main/src/modules/languages/python

languages.python.poetry.install.onlyInstallRootPackage

Whether to only install the root package (your project) should be installed, but no dependencies. See --only-root

Type: boolean

Default:

false

Declared by: - https://github.com/cachix/devenv/blob/main/src/modules/languages/python

languages.python.poetry.install.quiet

Whether poetry install should avoid outputting messages during devenv initialisation.

Type: boolean

Default:

false

Declared by: - https://github.com/cachix/devenv/blob/main/src/modules/languages/python

languages.python.poetry.install.verbosity

What level of verbosity the output of poetry install should have.

Type: one of “no”, “little”, “more”, “debug”

Default:

"no"

Declared by: - https://github.com/cachix/devenv/blob/main/src/modules/languages/python

languages.python.uv.enable

Whether to enable uv.

Type: boolean

Default:

false

Example:

true

Declared by: - https://github.com/cachix/devenv/blob/main/src/modules/languages/python

languages.python.uv.package

The uv package to use.

Type: package

Default:

pkgs.uv

Declared by: - https://github.com/cachix/devenv/blob/main/src/modules/languages/python

languages.python.uv.sync.enable

Whether to enable uv sync during devenv initialisation.

Type: boolean

Default:

false

Example:

true

Declared by: - https://github.com/cachix/devenv/blob/main/src/modules/languages/python

languages.python.uv.sync.packages

Sync for specific packages in the workspace. See --package.

Type: list of string

Default:

[ ]

Declared by: - https://github.com/cachix/devenv/blob/main/src/modules/languages/python

languages.python.uv.sync.allExtras

Whether to install all extras. See --all-extras.

Type: boolean

Default:

false

Declared by: - https://github.com/cachix/devenv/blob/main/src/modules/languages/python

languages.python.uv.sync.allGroups

Whether to install all groups. See --all-groups.

Type: boolean

Default:

false

Declared by: - https://github.com/cachix/devenv/blob/main/src/modules/languages/python

languages.python.uv.sync.allPackages

Sync all packages in the workspace. See --all-packages.

Type: boolean

Default:

false

Declared by: - https://github.com/cachix/devenv/blob/main/src/modules/languages/python

languages.python.uv.sync.arguments

Command line arguments pass to uv sync during devenv initialisation.

Type: list of string

Default:

[ ]

Declared by: - https://github.com/cachix/devenv/blob/main/src/modules/languages/python

languages.python.uv.sync.extras

Which extras to install. See --extra.

Type: list of string

Default:

[ ]

Declared by: - https://github.com/cachix/devenv/blob/main/src/modules/languages/python

languages.python.uv.sync.groups

Which dependency groups to install. See --group.

Type: list of string

Default:

[ ]

Declared by: - https://github.com/cachix/devenv/blob/main/src/modules/languages/python

languages.python.venv.enable

Whether to enable Python virtual environment.

Type: boolean

Default:

false

Example:

true

Declared by: - https://github.com/cachix/devenv/blob/main/src/modules/languages/python

languages.python.venv.quiet

Whether pip install should avoid outputting messages during devenv initialisation.

Type: boolean

Default:

false

Declared by: - https://github.com/cachix/devenv/blob/main/src/modules/languages/python

languages.python.venv.requirements

Contents of pip requirements.txt file. This is passed to pip install -r during devenv shell initialisation.

Type: null or strings concatenated with “\n” or absolute path

Default:

null

Declared by: - https://github.com/cachix/devenv/blob/main/src/modules/languages/python

languages.python.version

The Python version to use. This automatically sets the languages.python.package using nixpkgs-python.

Type: null or string

Default:

null

Example:

"3.11 or 3.11.2"

Declared by: - https://github.com/cachix/devenv/blob/main/src/modules/languages/python