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"
