Sat. Jan 17th, 2026

Nix is a functional package manager and build system that treats software environments as pure, declarative specifications rather than mutable system state.

Why Nix exists (the core problem it solves)

Traditional environment management (apt, conda, pip, system modules) suffers from:

  • Hidden global state (/usr/lib, /usr/include)
  • ABI mismatches (MPI, BLAS, glibc)
  • “Works on my machine” failures
  • CI environments drifting over time
  • Extremely fragile HPC / scientific stacks

Nix replaces this with a pure, content-addressed store (/nix/store) where:

  • Every dependency is immutable
  • Multiple versions coexist safely
  • Builds depend only on declared inputs


Installation

# A. with sudo (recomend: multi-user/daemon)
user@computer:sh <(curl -L https://nixos.org/nix/install) --daemon

# B. without sudo(single-user)
user@computer:sh <(curl -L https://nixos.org/nix/install) --no-daemon

Activate flakes



  - multi-user:

  sudo mkdir -p /etc/nix
  echo "experimental-features = nix-command flakes" | sudo tee /etc/nix/nix.conf
  sudo systemctl restart nix-daemon

  - single-user:

  mkdir -p ~/.config/nix
  echo "experimental-features = nix-command flakes" > ~/.config/nix/nix.conf

Write flake.nix

Python with PETSc (Better)

{
  description = "python dev environment with PETSc pinned via nixpkgs";

  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11";
    flake-utils.url = "github:numtide/flake-utils";
  };

  outputs = { self, nixpkgs, flake-utils }:
    flake-utils.lib.eachDefaultSystem (system:
      let
        pkgs = import nixpkgs { inherit system; };
        petsc = pkgs.petsc.overrideAttrs (old: {
          version = "3.23.6";
          src = pkgs.fetchurl {
            url = "https://web.cels.anl.gov/projects/petsc/download/release-snapshots/petsc-3.23.6.tar.gz";
            sha256 = "sha256-B+BJLFw40vxapt2YHEUAhvO4j4g03xEkeofUvs+4XHI=";
          };
        });
      in
      {
        devShells.default = pkgs.mkShell {
          packages = [
            petsc
            pkgs.openmpi
            pkgs.pkg-config
            pkgs.python312
            pkgs.poetry
            pkgs.stdenv.cc.cc.lib
            pkgs.zlib
            pkgs.xorg.libX11
            pkgs.gfortran.cc.lib
          ];

          PETSC_DIR = "${petsc}";
          OMPI_MCA_btl = "self,vader,tcp";

          shellHook = ''
            export PYTHON_KEYRING_BACKEND=keyring.backends.null.Keyring
            export POETRY_VIRTUALENVS_CREATE=true
            export POETRY_VIRTUALENVS_IN_PROJECT=true
            export POETRY_VIRTUALENVS_PREFER_ACTIVE_PYTHON=true
            export FLUXFEM_LD_LIBRARY_PATH="${pkgs.stdenv.cc.cc.lib}/lib:${pkgs.zlib}/lib:${pkgs.xorg.libX11}/lib:${pkgs.gfortran.cc.lib}/lib"

            poetry() {
              LD_LIBRARY_PATH="$FLUXFEM_LD_LIBRARY_PATH''${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" command poetry "$@"
            }

            python() {
              LD_LIBRARY_PATH="$FLUXFEM_LD_LIBRARY_PATH''${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" command python "$@"
            }
            echo "PETSc: ${petsc.version}"
            echo "Python: using Nix python at $(which python)"
            echo "Poetry: venv in project, prefer active python"
          '';
        };
      });
}

Activate virtualenv

Python installed with Nix is readonly, activate virtualenv (poetry), and install packages with this.

# if installation failed before,
poetry env remove --all
rm -rf .venv

# This is activated in SHELL in flake.nix though, just in case
poetry config virtualenvs.create true
poetry env use $(which python)
poetry install --extras petsc

PETSc Only

{
  description = "dev environment with PETSc pinned via nixpkgs";

  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11";
    flake-utils.url = "github:numtide/flake-utils";
  };

  outputs = { self, nixpkgs, flake-utils }:
    flake-utils.lib.eachDefaultSystem (system:
      let
        pkgs = import nixpkgs { inherit system; };
        petsc = pkgs.petsc.overrideAttrs (old: {
          version = "3.23.6";
          src = pkgs.fetchurl {
            url = "https://web.cels.anl.gov/projects/petsc/download/release-snapshots/petsc-3.23.6.tar.gz";
            sha256 = "sha256-B+BJLFw40vxapt2YHEUAhvO4j4g03xEkeofUvs+4XHI=";
          };
        });
      in
      {
        devShells.default = pkgs.mkShell {
          packages = [
            petsc
            pkgs.openmpi
            pkgs.pkg-config
          ];

          PETSC_DIR = "${petsc}";
          OMPI_MCA_btl = "self,vader,tcp";

          shellHook = ''
            echo "PETSc: ${petsc.version}"
            echo "Python: use pyenv (not provided by Nix)"
          '';
        };
      });
}

Install PETSc

user@computer:git -C /home/user/project/p1 add flake.nix flake.lock
user@computer:nix develop

Verify PETSc PATH

user@computer:~/project/p1$ echo $PETSC_DIR
/nix/store/gkiw0bg0gs3z8x57gwp7rzxbialnkg7g-petsc-3.23.6

Install Dependencies

poetry install --with dev --extras petsc

[project]
name = "fluxfem"
version = "0.1.7"
description = ""
authors = [
    {name = "Kohei Watanabe",email = "koheitech001@gmail.com"}
]
readme = "README.md"
requires-python = ">=3.12,<3.14"
classifiers = [
    "Programming Language :: Python :: 3",
    "Programming Language :: Python :: 3.11",
    "Programming Language :: Python :: 3.12",
    "Programming Language :: Python :: 3.13",
]
dependencies = [
    "pyvista (>=0.46.4,<0.47.0)",
    "meshio (>=5.3.5,<6.0.0)",
    "matplotlib (>=3.10.7,<4.0.0)",
    # Note: jax versioning currently around 0.8.x. Allow up to next minor.
    "jax (>=0.8.2,<0.9.0)",
    "jaxlib (>=0.8.2,<0.9.0)",
]

[project.optional-dependencies]
# Keep petsc4py aligned with the PETSc build referenced by PETSC_DIR.
petsc = ["petsc4py"]

[tool.poetry]
name = "fluxfem"
version = "0.1.7"
description = "FluxFEM: A weak-form-centric differentiable finite element framework in JAX"
authors = ["Kohei Watanabe <koheitech001@gmail.com>"]
readme = "README.md"
license = "Apache-2.0"
packages = [
  { include = "fluxfem", from = "src" }
]


[tool.poetry.dependencies]
python = ">=3.12,<3.14"
pyvista = ">=0.46.4,<0.47.0"
meshio = ">=5.3.5,<6.0.0"
matplotlib = ">=3.10.7,<4.0.0"
jax = ">=0.8.2,<0.9.0"
jaxlib = ">=0.8.2,<0.9.0"
petsc4py = { version = "==3.23.6", optional = true }
pyproject-toml = "^0.1.0"
pyproject = "^1!0.1.2"


[tool.poetry.group.dev]
optional = true

[tool.poetry.group.dev.dependencies]
pytest = ">=9.0.2,<10.0.0"
pytest-cov = "^5.0.0"
scikit-fem = ">=11.0.0,<12.0.0"
line-profiler = ">=4.2.0,<5.0.0"
memory-profiler = ">=0.61.0,<0.62.0"
flake8 = "^7.2.0"
sphinx = { version = "^8.2.3", python = ">=3.11" }
recommonmark = { version = "^0.7.1", python = ">=3.11" }
sphinx-rtd-theme = { version = "^3.0.2", python = ">=3.11" }
myst-parser = { version = "^4.0.1", python = ">=3.11" }
sphinx-autodoc-typehints = { version = "^3.2.0", python = ">=3.11" }
sphinx-sitemap = { version = "^2.6.0", python = ">=3.11" }
shapely = "^2.1.2"

[tool.poetry.extras]
petsc = ["petsc4py"]

[build-system]
requires = ["poetry-core>=2.0.0,<3.0.0"]
build-backend = "poetry.core.masonry.api"