Apptainer
How NowWhat Apptainer containers, modules, wrappers, overlays, and GPU images work.
This page explains how Apptainer-based modules behave on NowWhat from a user point of view.
The goal is to help you use these modules correctly in interactive sessions and in SLURM jobs, especially when you need Python or R packages on top of the base container.
What These Modules Provide
An Apptainer module exposes software through ordinary shell commands, but those commands actually run inside a container image managed by the platform.
Typical examples are:
apptainer-python/3.11apptainer-R/4.5apptainer-jupyter/latestapptainer-pytorch/25.03
After you load one of these modules, you usually work with standard commands such as:
pythonpipRRscriptjupyterjupyter-labrstudiobashnvcc
In most cases you do not need to write apptainer exec ... yourself. The module adds wrapper commands to your PATH, and those wrappers start the corresponding command inside the correct container.
Basic Usage Pattern
Load only the module you need:
module purge
module load apptainer-python/3.11
python --versionThe same pattern applies in job scripts:
module purge
module load apptainer-R/4.5
R --versionThis is the recommended interface. Treat the module as the entry point, not the container image path.
What Happens When You Load the Module
When you load an Apptainer module, the modulefile mainly does three things:
- it prepends a wrapper directory to
PATH - it exports a few container-related environment variables
- for Python and R images, it sets the user package locations expected inside the container
This design keeps the module lightweight. The actual runtime logic lives in the wrapper scripts that the module exposes.
Wrapper Commands and sapp
Each module can expose one or more commands.
Examples:
apptainer-pythonexposespython,pip, andsappapptainer-RexposesR,Rscript,rstudio, andsappapptainer-cudaexposesbash,nvcc,nvidia-smi, andsapp
The sapp command is the generic entry point for running an arbitrary command inside the container:
module purge
module load apptainer-python/3.11
sapp python -c "import sys; print(sys.version)"Use sapp when:
- the module does not expose the exact command you want as a dedicated wrapper
- you want to run a custom command directly inside the container
Use the dedicated wrappers such as python, R, jupyter, or nvcc when available, because they are clearer and easier to read in scripts.
Utility Commands
NowWhat also provides apptainer-utils for helper commands such as export-container. See Apptainer Utils.
The Container Image Variable
Each module also exports an environment variable pointing to the underlying .sif image.
The variable name is derived from the module name by uppercasing it and replacing - with _.
Examples:
apptainer-python->APPTAINER_PYTHONapptainer-R->APPTAINER_Rapptainer-rstudio-server->APPTAINER_RSTUDIO_SERVER
Example:
module purge
module load apptainer-python/3.11
echo "$APPTAINER_PYTHON"
apptainer exec "$APPTAINER_PYTHON" python --versionYou usually do not need this variable for normal work, but it is useful when you need a manual apptainer exec for debugging or advanced workflows.
Persistent User Overlay
For many Apptainer modules, the base image is read-only but each user also gets a personal writable overlay image stored in home:
$HOME/containers/<module>/<version>.imgImportant points:
- the overlay is created automatically the first time you run a wrapper from that module
- it is a sparse image with a default size of
4 GB - it is private to your account
- it persists across sessions and jobs
This is the mechanism that lets Python and R packages survive after installation. You are not modifying the shared base image; you are adding your own layer on top of it.
How Concurrency Works
Overlay access is intentionally conservative.
By default, wrappers run with:
HPC_CONTAINER_OVERLAY_MODE=autoIn auto mode:
- the first running instance that gets the lock mounts the overlay read-write
- a concurrent instance that cannot get that lock runs without the overlay
That second behavior is important: it does not see your personal overlay contents. It only sees the shared base container.
In practice this means:
- if you installed user packages and want them to be visible, avoid launching many simultaneous sessions from the same module unless you understand the consequences
- concurrent read-only commands may show a different environment from the one seen by the instance that holds the overlay lock
You can change the runtime behavior explicitly:
export HPC_CONTAINER_OVERLAY_MODE=rw
module load apptainer-python/3.11
pythonModes:
auto: default, best general-purpose behaviorrw: require read-write overlay access; if the overlay is busy, the command failsro: mount the overlay read-only; useful when you want consistent visibility of already-installed content without allowing writes
ro and rw must be set before launching the wrapped command.
Python Modules
Python-based modules set up a persistent user installation area inside the container and configure pip to use it.
When you load a Python container module, the modulefile sets:
PIP_USER=1PYTHONUSERBASE=/srv/pythonAPPTAINERENV_PYTHONUSERBASE=/srv/pythonPIP_DISABLE_PIP_VERSION_CHECK=1
It also sets PIP_CACHE_DIR:
$SCRATCH/.pip-cacheifSCRATCHis defined- otherwise
$HOME/.cache/pip
The practical consequence is that this works as expected:
module purge
module load apptainer-python/3.11
pip install --user numpy
python -c "import numpy; print(numpy.__version__)"Notes:
pip install --userwrites into your personal overlay-backed area inside the container- the installed packages remain available in later sessions
- if another process already holds the overlay in read-write mode,
pip install --user ...fails instead of silently running without write access
This is a good safety property: package installation either gets writable access or stops.
R Modules
R-based modules configure a user library path inside the container and preserve it through the overlay.
When you load an R container module, the modulefile sets:
R_LIBS_USER=/srv/R/libraryAPPTAINERENV_R_LIBS_USER=/srv/R/libraryAPPTAINERENV_R_LIBS=/srv/R/library
This means user-installed R packages are expected to live in that container-side path, backed by your overlay.
Typical usage:
module purge
module load apptainer-R/4.5
RThen inside R:
install.packages("data.table")
library(data.table)The installed package remains in your personal overlay for future runs of the same module version.
As with Python, concurrent sessions matter: if a second instance runs without the overlay, it will not see packages that only exist in your personal layer.
GPU-Enabled Containers
Several modules are configured to pass GPU support automatically when their wrappers start the container.
For those modules, the wrapper uses apptainer exec --nv ... instead of plain apptainer exec ....
This is relevant for modules such as:
apptainer-pytorchapptainer-tensorflowapptainer-cuda- the Python and R images, which are also configured to allow GPU passthrough when used on GPU nodes
What this means for users:
- on a GPU node, the wrapped command can access NVIDIA devices without extra wrapper logic from you
- on a non-GPU node, the module still loads, but GPU-dependent workloads obviously cannot use devices that are not present
You still need to request GPU resources through SLURM when your workload requires them.
Shared Project Bind Mount
All wrapper commands bind /projects from the host into the container at the same path:
/projects -> /projectsThis means paths under /projects remain stable when you move between host-side shell usage and containerized commands.
If your workflow depends on shared project data, use that path consistently.
Prompt and Container Identity
The wrappers also export container identity variables into the runtime environment:
CONTAINER_NAMECONTAINER_VERSIONCONTAINER_KEY
They also set matching APPTAINERENV_* variables so the values are visible inside the container.
Interactive shells started through the wrappers get a prompt marker similar to:
[apptainer-python/3.11] [...]This is only a convenience feature, but it helps you notice when you are operating inside a container-backed environment.
Jupyter and RStudio Wrappers
Some modules expose service-style commands such as jupyter, jupyter-lab, or rstudio.
These are still container-backed wrappers. The main user-facing rule does not change:
- start them on compute nodes, not on the login node
- load the module first
- then run the exported command normally
For RStudio specifically, the wrapper supplies sensible defaults if you do not pass them explicitly:
- bind address defaults to
0.0.0.0 - port defaults to
8788
You can still override them with arguments such as:
rstudio --ip 0.0.0.0 --port 8787For complete service workflows, see the dedicated Jupyter and RStudio Server pages.
Recommended User Practices
- start with
module purge - load exactly one version of the Apptainer module you need
- use the exported wrapper commands rather than hand-written
apptainer exec ... - install Python packages with
pip install --user - install R packages through the usual R mechanisms and let
R_LIBS_USERhandle placement - avoid concurrent sessions from the same module when you depend on packages stored in your personal overlay
- run notebook servers, RStudio, and GPU workloads only inside appropriate SLURM allocations
Troubleshooting Expectations
If a command works after module load but does not see a package you previously installed, the most likely causes are:
- you loaded a different module version
- the package was installed in your personal overlay for another module
- the current process is running without the overlay because another instance already holds the read-write lock
If you need stable visibility of already-installed content across multiple readers, try a read-only overlay run:
export HPC_CONTAINER_OVERLAY_MODE=ro
module purge
module load apptainer-python/3.11
python -c "import numpy"If you need to install or update packages, use a single writable session instead:
export HPC_CONTAINER_OVERLAY_MODE=rw
module purge
module load apptainer-python/3.11
pip install --user numpyIf a required module or wrapper command is missing, or if container behavior looks inconsistent across nodes, contact nowwhat@stat.unipd.it.
Current Catalogue
- Containers lists all Apptainer modules and image paths.
- Container Variables documents exported container variables.
- Apptainer Utils documents helper commands such as
export-container.