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

Tcl

non-hierarchical

share/spack/modules

share/spack/templates/modules/modulefile.tcl

Environment Modules, Lmod

Lua

hierarchical

share/spack/lmod

share/spack/templates/modules/modulefile.lua

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:

  1. overriding certain callback APIs in the Python packages

  2. writing specific rules in the modules.yaml configuration file

  3. writing 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_compilers lists the compilers whose packages go in the Core layer.

  • core_specs lists any additional packages that should also go in Core, bypassing the normal hierarchy.

  • hierarchy lists the virtual packages that define the additional layers beyond Core and Compiler.

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.yaml applied to matching packages

  • Callbacks defined in package.py for 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 autoloading

  • run: autoload direct run type dependencies

  • direct: autoload direct link and run type dependencies

  • all: 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

<prefix>/bin

PATH

<prefix>/man

MANPATH

<prefix>/share/man

MANPATH

<prefix>/share/aclocal

ACLOCAL_PATH

<prefix>/lib/pkgconfig

PKG_CONFIG_PATH

<prefix>/lib64/pkgconfig

PKG_CONFIG_PATH

<prefix>/share/pkgconfig

PKG_CONFIG_PATH

<prefix>

CMAKE_PREFIX_PATH

<prefix>/lib (macOS)

DYLD_FALLBACK_LIBRARY_PATH

<prefix>/lib64 (macOS)

DYLD_FALLBACK_LIBRARY_PATH

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: sets BAR=bar for every module.

  • For specs matching ^mpi::: BAR is overridden to baz. The trailing :: clears all previously matched rules, so the all block’s BAR=bar does not carry over.

  • zlib: prepends {prefix}/lib to LD_LIBRARY_PATH.

  • zlib%gcc@13: unsets FOOBAR.

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.