Modules (modules.yaml)¶
The use of module systems to manage user environments in a controlled way is a common practice at HPC centers that is sometimes embraced also by individual programmers on their development machines. To support this common practice Spack integrates with Environment Modules and Lmod by providing post-install hooks that generate module files and commands to manipulate them.
Modules are one of the several ways you can use installed packages, along with spack load and environments.
Quick start¶
Spack can generate both Tcl and Lua module files, either with a post-install hook or at user’s request through a command.
If you’re using the default configuration values, you can start by generating Tcl module files for all currently installed packages:
$ spack module tcl refresh
To generate Lua module files simply use the spack module lmod command instead of spack module tcl.
Once module files are in place, add the Tcl module directory generated above to your module path:
$ module use $SPACK_ROOT/share/spack/modules/$(spack arch)
You can now browse and load the available modules:
$ module avail
------------------------------------------------------------ <spack-root>/share/spack/modules/linux-ubuntu24.04-skylake ------------------------------------------------------------
bison/3.8.2-gcc-13.3.0-hs4pc4c flex/2.6.3-gcc-13.3.0-jz6pfzf libevent/2.1.12-gcc-13.3.0-5k3sh64 openmpi/5.0.10-gcc-13.3.0-fjv7c7n
ca-certificates-mozilla/2026-03-19-none-none-som6bt4 gcc-runtime/13.3.0-none-none-5opaxqi libpciaccess/0.17-gcc-13.3.0-rcke4u2 openssh/10.3p1-gcc-13.3.0-bwrgshz
cmake/3.31.11-gcc-13.3.0-g2bzgpi gromacs/2026.1-gcc-13.3.0-lyxhacq libxcrypt/4.5.2-gcc-13.3.0-2snor6m openssl/3.6.1-gcc-13.3.0-fhuz67z
compiler-wrapper/1.1.0-none-none-zr6dbk4 hwloc/2.13.0-gcc-13.3.0-a4elwgb nghttp2/1.67.1-gcc-13.3.0-oofdxin pmix/6.1.0-gcc-13.3.0-gwijn2q
curl/8.20.0-gcc-13.3.0-jdcsqbb krb5/1.22.2-gcc-13.3.0-cg4l6qb numactl/2.0.19-gcc-13.3.0-p7sk7en prrte/4.1.0-gcc-13.3.0-wrgywxy
fftw/3.3.11-gcc-13.3.0-addcjv5 libedit/3.1-20251016-gcc-13.3.0-fv2f7sz openblas/0.3.33-gcc-13.3.0-ew5pzcz util-macros/1.20.2-none-none-l3eawtn
$ module load openmpi/5.0.10-gcc-13.3.0-fjv7c7n
The default module names encode the package version, compiler, and a short hash to distinguish builds with different configurations. Of course, it’s possible to customize the naming scheme to match your site’s conventions, as the following sections will show.
Module file customization¶
The table below summarizes the essential information associated with the different file formats that can be generated by Spack:
Language |
Default hierarchical mode |
Default root directory |
Default template file |
Compatible tools |
|---|---|---|---|---|
|
non-hierarchical |
|
|
Environment Modules, Lmod |
|
hierarchical |
|
|
Lmod |
Flat and hierarchical module files¶
In flat (non-hierarchical) mode, all module files are installed in a single directory. Default settings are such that:
Each module name encodes the package version, compiler, and a hash to distinguish builds with different configurations.
Every installed package has a visible module, and dependencies are made available through autoloading.
The naming scheme can be customized as the Naming and projections section shows.
In hierarchical mode, module files are organized into layers: Core, Compiler, and optionally additional layers such as mpi, lapack, or python.
Loading a compiler module extends MODULEPATH to reveal the packages built with that compiler.
Similarly, loading an MPI module reveals the MPI-dependent packages, and so on.
Users are therefore only offered packages that are coherent with their loaded environment.
Flat mode is the default for tcl, while hierarchical mode is the default for lmod, but either generator supports either mode.
Set hierarchical: true under the tcl key to enable hierarchical Tcl modules, or hierarchical: false under the lmod key to generate flat Lua modules.
See Hierarchical module files for the full configuration options and tool-version requirements.
Spack ships with sensible defaults for the generation of module files, but you can customize many aspects of it to accommodate package or site specific needs. In general you can override or extend the default behavior by:
overriding certain callback APIs in the Python packages
writing specific rules in the
modules.yamlconfiguration filewriting your own templates to override or extend the defaults
Overriding callback APIs lets you express changes in the run-time environment that are needed to use the installed software properly, e.g. injecting variables from language interpreters into their extensions. Configuration rules and custom templates instead permit you to fine-tune the filesystem layout, content and creation of module files to meet site-specific conventions.
Configuration structure¶
The configuration files that control module generation behavior are named modules.yaml.
The default configuration looks like this:
# -------------------------------------------------------------------------
# This is the default configuration for Spack's module file generation.
#
# Settings here are versioned with Spack and are intended to provide
# sensible defaults out of the box. Spack maintainers should edit this
# file to keep it current.
#
# Users can override these settings by editing the following files.
#
# Per-spack-instance settings (overrides defaults):
# $SPACK_ROOT/etc/spack/modules.yaml
#
# Per-user settings (overrides default and site settings):
# ~/.spack/modules.yaml
# -------------------------------------------------------------------------
modules:
# This maps paths in the package install prefix to environment variables
# they should be added to. For example, <prefix>/bin should be in PATH.
prefix_inspections:
./bin:
- PATH
./man:
- MANPATH
./share/man:
- MANPATH
./share/aclocal:
- ACLOCAL_PATH
./lib/pkgconfig:
- PKG_CONFIG_PATH
./lib64/pkgconfig:
- PKG_CONFIG_PATH
./share/pkgconfig:
- PKG_CONFIG_PATH
./:
- CMAKE_PREFIX_PATH
# These are configurations for the module set named "default"
default:
# Where to install modules
roots:
tcl: $spack/share/spack/modules
lmod: $spack/share/spack/lmod
# What type of modules to use ("tcl" and/or "lmod")
enable: []
tcl:
all:
autoload: direct
# Default configurations if lmod is enabled
lmod:
all:
autoload: direct
hierarchy:
- mpi
You can define one or more module sets, each of which can be configured separately with regard to install location, naming scheme, inclusion and exclusion, autoloading, et cetera.
The default module set is aptly named default.
All Spack commands that operate on modules apply to the default module set, unless another module set is specified explicitly (with the --name flag).
To automatically generate module files during package installation, add the desired module systems to the enable list:
modules:
default:
enable:
- tcl
- lmod
You can configure the behavior of either module system separately, under a key corresponding to the generator being customized:
modules:
default:
tcl:
# contains environment modules specific customizations
lmod:
# contains lmod specific customizations
In general, the configuration options that you can use in modules.yaml will either change the layout of the module files on the filesystem, or they will affect their content.
For the latter point it is possible to use spec patterns to fine-tune the set of packages on which the modifications should be applied.
The default module root can be overridden for any module set by changing the roots key of the configuration.
For example, to install tcl modules to a custom path:
modules:
default:
roots:
tcl: /path/to/install/tcl/modules
By default, an architecture-specific directory is added to the root directory.
A module set may override that behavior by setting the arch_folder config value to false.
modules:
default:
roots:
tcl: /path/to/install/tcl/modules
arch_folder: false
Module layout¶
By default, Spack encodes the package version, compiler, and a short hash into every module name to distinguish builds with different configurations. The options in this section let you change where module files are placed on the filesystem, how they are named, whether to arrange them in a hierarchy, and which version is the default.
Naming and projections¶
Spack provides three options to make module names shorter and easier to read. The first is a global setting to adjust the hash length. It accepts values from 0 to 32 (default: 7):
modules:
default:
tcl:
hash_length: 7
A hash length of 0 removes the hash completely, making the module name more readable, but also more subject to naming conflicts.
The second option is suffixes, which appends a string to the names of modules matching a spec.
For example, the following configuration adds a python3.12 suffix to any package built with Python 3.12:
modules:
default:
tcl:
all:
suffixes:
^python@3: "python{^python.version.up_to_2}"
^openblas: "openblas"
This is useful to know which version of Python a set of Python extensions is associated with.
Likewise, the openblas string is attached to any program that has openblas in the spec, most likely via the +blas variant specification.
The third, and most flexible, option is to change the entire naming convention using the projections format covered in View Projections:
modules:
default:
tcl:
projections:
all: "{name}/{version}-{compiler.name}-{compiler.version}-module"
^mpi: "{name}/{version}-{^mpi.name}-{^mpi.version}-{compiler.name}-{compiler.version}-module"
Note that the default projection for module files differs by mode:
In hierarchical mode it is
{name}/{version}In flat mode it is
{name}/{version}-{compiler.name}-{compiler.version}
Hierarchical module files¶
Three keys control the shape of the hierarchy:
core_compilerslists the compilers whose packages go in theCorelayer.core_specslists any additional packages that should also go inCore, bypassing the normal hierarchy.hierarchylists the virtual packages that define the additional layers beyondCoreandCompiler.
The configuration below generates a hierarchy in which the python, lapack, and mpi layers can be switched independently:
modules:
default:
lmod:
core_compilers:
- "gcc@13"
core_specs:
- "r"
hierarchy:
- "mpi"
- "lapack"
- "python"
For tcl, whose default layout is flat, add hierarchical: true to the same configuration (this requires either Environment Modules >= 5.6 or Lmod >= 8.7.31).
Note that core_specs bypasses the hierarchy that allows the module tool to safely switch between coherent software stacks, so the user is responsible for maintaining consistency among those packages.
Default module versions¶
To pin a specific version as the default, add a defaults key to your modules configuration:
modules:
my-module-set:
tcl:
defaults:
- gcc@10.2.1
- hdf5@1.2.10+mpi+hl%gcc
The spec can be as specific as needed. If multiple packages in the same directory match, the last one generated wins.
Module content¶
When a user loads a module, the module system executes the module file, which sets environment variables and optionally loads dependencies. Spack populates module files from three sources:
Prefix inspections derived automatically from the installation layout
Rules in
modules.yamlapplied to matching packagesCallbacks defined in
package.pyfor package-specific logic
The options in this section let you control which dependencies are autoloaded, what environment variables are set and for which packages, and which module files are generated at all.
Autoloading and hiding dependencies¶
Each package’s module file sets only the environment variables for that package itself. Autoloading handles the rest: when a module is loaded, Spack can automatically load the modules for its dependencies, so users do not need to track them manually.
The autoload key controls the autoloading behavior, and can take one of these values:
none: no autoloadingrun: autoload direct run type dependenciesdirect: autoload direct link and run type dependenciesall: autoload all dependencies
direct is the most correct choice, but run is often sufficient and may be faster to load.
hide_implicits: true limits module avail to only the packages you explicitly installed, while still autoloading hidden dependencies.
We recommend enabling both options together:
modules:
default:
tcl:
hide_implicits: true
all:
autoload: direct # or 'run'
lmod:
hide_implicits: true
all:
autoload: direct # or 'run'
This ensures all runtime variables are set correctly, limits visible modules to what users explicitly installed, and makes shorter module names easier to use without conflicts (see Naming and projections).
Module conflicts¶
Tcl and Lua modules allow for explicit conflicts between module files.
Using the conflict key under a spec pattern, you can prevent two incompatible modules from being loaded at the same time:
modules:
default:
tcl:
all:
conflict:
- "{name}"
- "intel/14.0.1"
This prevents loading any other version of the same package (via {name}) or intel/14.0.1.
For Lmod, and for Environment Modules versions prior to 4.2, the conflict must be expressed on both module files conflicting with each other.
Global environment modifications¶
Spack automatically adds environment variable modifications to every module file by inspecting the installation prefix.
The prefix_inspections section maps relative paths inside the prefix to the environment variables that should be updated with them.
In the configuration, paths are written relative to the installation prefix, so ./bin means <prefix>/bin, and ./ means <prefix> itself:
modules:
prefix_inspections:
./bin:
- PATH
./man:
- MANPATH
./:
- CMAKE_PREFIX_PATH
Unlike other module settings, prefix_inspections placed at the top modules level applies to all module sets at once.
An inspection is only applied when the corresponding subdirectory exists in the installation prefix.
The table below lists the default inspections:
Path |
Environment variable |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
On Linux, LD_LIBRARY_PATH is omitted: Spack packages embed RPATHs, making it unnecessary, and setting it globally affects system executables.
To suppress a variable from all module files, use exclude_env_vars:
modules:
default:
tcl:
all:
filter:
exclude_env_vars: ["CPATH", "LIBRARY_PATH"]
Selective environment modifications¶
The environment key lets you set, prepend, or unset variables for any set of packages matching a spec pattern.
This is useful when you want to apply a change to many packages at once, or when you prefer to keep the logic in configuration rather than in package.py.
The following example shows the four main pattern forms and the operations available under environment:
modules:
default:
tcl:
# Selects every package
all:
environment:
set:
BAR: "bar"
# Selects MPI-dependent packages. The :: clears previously matched rules
^mpi::
environment:
set:
BAR: "baz"
# Selects any zlib package
zlib:
environment:
prepend_path:
LD_LIBRARY_PATH: "{prefix}/lib"
# Selects zlib compiled with gcc@13
zlib%gcc@13:
environment:
unset:
- FOOBAR
Each rule selects a set of packages and applies the corresponding modifications:
all: setsBAR=barfor every module.For specs matching
^mpi:::BARis overridden tobaz. The trailing::clears all previously matched rules, so theallblock’sBAR=bardoes not carry over.zlib: prepends{prefix}/libtoLD_LIBRARY_PATH.zlib%gcc@13: unsetsFOOBAR.
The all block is always evaluated first regardless of where it appears in the file.
All other rules are evaluated top to bottom.
As general advice, set only the variables a package actually needs: unexpected interactions with other tools are hard to debug.
Package-specific environment modifications¶
Two methods in package.py let you inject environment modifications directly into module files.
setup_run_environment sets variables based on the package’s own spec:
def setup_run_environment(self, env: EnvironmentModifications) -> None:
if self.spec.satisfies("+foo"):
env.set("FOO", "bar")
setup_dependent_run_environment allows a package to set variables in the module files of its dependents.
This is used in interpreter packages such as python, r, and perl.
When a dependent is built, the interpreter prepends the dependent’s prefix to its search path (PYTHONPATH, R_LIBS, or PERL5LIB) so the interpreter can locate it at runtime.
A simplified python package looks like this:
def setup_dependent_run_environment(
self, env: EnvironmentModifications, dependent_spec: Spec
) -> None:
if dependent_spec.package.extends(self.spec):
env.prepend_path("PYTHONPATH", dependent_spec.prefix.lib.python)
This ensures every Python extension has its library directory on PYTHONPATH without repeating the logic in each extension’s setup_run_environment.
Modules relative to environment views¶
When a Spack environment uses a view, you can configure a module set to generate module files relative to the view paths instead of the install tree. This requires a view whose projection assigns each package a unique subdirectory.
The use_view key controls this behavior:
true: use the default view of the environment.a view name (e.g.
my_view): use that named view; prefix inspections are then relative to each package’s path in the view.false: disabled (the default).
spack:
modules:
view_relative_modules:
use_view: my_view
prefix_inspections:
./bin:
- PATH
view:
my_view:
root: /path/to/my/view
projections:
all: "{name}-{hash}"
The view key is discussed in detail in Configuring environment views.
With this configuration the generated module for package foo would set PATH to include /path/to/my/view/foo-<hash>/bin instead of /spack/prefix/foo/bin.
This is useful for large deployments where view paths are simpler and more stable than install-tree paths.
Excluding packages¶
The exclude and include keys control which packages get module files generated.
For example, to suppress module files for all packages compiled with the system compiler except gcc and llvm themselves:
modules:
default:
tcl:
include: ["gcc", "llvm"] # include will have precedence over exclude
exclude: ["%gcc@13"] # Assuming gcc@13 is the system compiler
This suppresses module files for every package compiled with gcc@13, except gcc and llvm.
Combining exclude and autoload is safe: when a dependency has no module file, autoload simply omits its load statement.
Maintaining Module Files¶
Spack provides spack module tcl and spack module lmod commands for managing module files.
The available subcommands are:
$ spack module tcl --help
usage: spack module tcl [-h] [-n MODULE_SET_NAME] SUBCOMMAND ...
positional arguments:
SUBCOMMAND
refresh regenerate module files
find find module files for packages
rm remove module files
loads prompt the list of modules associated with a constraint
setdefault set the default module file for a package
options:
-h, --help show this help message and exit
-n, --name MODULE_SET_NAME
named module set to use from modules configuration
The refresh subcommand regenerates module files.
Use the optional constraint argument to regenerate only packages matching a spec pattern.
Pass --delete-tree to delete the entire module tree before regenerating, which is useful to handle a radical layout change.
$ spack module tcl refresh --help
usage: spack module tcl refresh [-hy] [--delete-tree] [--upstream-modules] ...
positional arguments:
installed_specs constraint to select a subset of installed packages
options:
--delete-tree delete the module file tree before refresh
--upstream-modules generate modules for packages installed upstream
-h, --help show this help message and exit
-y, --yes-to-all assume "yes" is the answer to every confirmation request
The rm subcommand deletes module files.
By default, Spack asks for confirmation before deleting; pass -y to skip the prompt in scripts.
$ spack module tcl rm --help
usage: spack module tcl rm [-hy] ...
positional arguments:
installed_specs constraint to select a subset of installed packages
options:
-h, --help show this help message and exit
-y, --yes-to-all assume "yes" is the answer to every confirmation request
The find subcommand translates a spec into its module name, which is useful for scripting:
$ spack module tcl find --help
usage: spack module tcl find [-hr] [--full-path] ...
positional arguments:
installed_specs constraint to select a subset of installed packages
options:
--full-path display full path to module file
-h, --help show this help message and exit
-r, --dependencies recursively traverse spec dependencies
$ spack module tcl find openmpi
openmpi/5.0.6-gcc-13.3.0-fjv7c7n
The setdefault subcommand marks a specific module version as the default, creating a default symlink:
$ spack module lmod setdefault --help
usage: spack module lmod setdefault [-h] ...
positional arguments:
installed_specs constraint to select a subset of installed packages
options:
-h, --help show this help message and exit
Using Spack modules in shell scripts¶
Spack’s shell functions and the module command are only available after sourcing the appropriate setup file.
Assuming Spack is installed in $SPACK_ROOT, run the appropriate command for your shell:
# For bash/zsh/sh
$ . $SPACK_ROOT/share/spack/setup-env.sh
# For tcsh/csh
$ source $SPACK_ROOT/share/spack/setup-env.csh
# For fish
$ . $SPACK_ROOT/share/spack/setup-env.fish
To have Spack’s shell support available at every login, add the appropriate line above to your shell’s startup file (.profile, .bashrc, or .cshrc).
spack module tcl loads¶
spack module tcl loads (or spack module lmod loads) generates module load statements for a spec.
This is useful in scripts where calling spack load directly would be too slow.
The --dependencies flag includes load statements for all dependencies.
This is usually not needed since Spack packages embed RPATHs, but some packages, in particular Python extensions, do not.
$ spack module tcl loads --dependencies openmpi
# hwloc@2.11.2%gcc@13.3.0 arch=linux-ubuntu24.04-x86_64
module load hwloc/2.11.2-gcc-13.3.0-o7qgalw
# numactl@2.0.19%gcc@13.3.0 arch=linux-ubuntu24.04-x86_64
module load numactl/2.0.19-gcc-13.3.0-p7sk7en
# pmix@6.0.0%gcc@13.3.0 arch=linux-ubuntu24.04-x86_64
module load pmix/6.0.0-gcc-13.3.0-gwijn2q
# openmpi@5.0.6%gcc@13.3.0 arch=linux-ubuntu24.04-x86_64
module load openmpi/5.0.6-gcc-13.3.0-fjv7c7n
The output can be sourced directly using process substitution:
$ source <( spack module tcl loads --dependencies <spec> )
Module Prefixes¶
On some systems, modules are automatically prefixed with a string.
Use --prefix to tell spack module tcl loads about it.
For example, on a system where modules are prefixed with the architecture string, without --prefix the generated module load statement will not match the actual module name:
$ module avail
linux-SuSE11-x86_64/antlr/2.7.7-gcc-5.3.0-bdpl46y
$ spack module tcl loads antlr
# antlr@2.7.7%gcc@5.3.0~csharp+cxx~java~python arch=linux-SuSE11-x86_64
module load antlr/2.7.7-gcc-5.3.0-bdpl46y
$ spack module tcl loads --prefix linux-SuSE11-x86_64/ antlr
# antlr@2.7.7%gcc@5.3.0~csharp+cxx~java~python arch=linux-SuSE11-x86_64
module load linux-SuSE11-x86_64/antlr/2.7.7-gcc-5.3.0-bdpl46y
The same --prefix option is available for spack module lmod loads.