Lesser known features

Environment Modules provides many capabilities beyond the commonly used module load command. Some features are lesser known, despite being very useful for users, modulefile developers, and site administrators.

This document gathers and explains a selection of these features through practical examples and common use cases.

It originates from the presentation Beyond "module load": Exploring the Capabilities of Environment Modules given at HPSFCon 2026. Original slides and video demonstrations can be found on the event session page.

Short command names

Most Modules sub-commands can be abbreviated. The ml command also provides a shorter alternative interface for common operations.

Standard command

Short form

module <cmd>

ml <cmd>

module avail

module av

module purge

module pu

module list

ml

module load <module>

ml <module>

module unload <module>

ml -<module>

Display/Parsing

--output=LIST

The --output, or -o, option customizes the information displayed by Modules commands.

It is supported by module avail, list, and spider sub-commands.

By default, these commands display additional formatting elements such as modulepaths, tags, default markers, or variant information. With --output, it is possible to restrict the displayed information to only the needed fields.

This option is especially useful when parsing command output in shell scripts, Python programs, or monitoring tools.

For example, with the following available modulefiles:

$ module avail
------------------- /usr/share/modulefiles ------------------
gcc/8.3  gcc/11.1  gcc/14.0  openmpi/5.0.8

When LIST is set to an empty value, only module names are displayed:

$ module avail -o ''
gcc/8.3  gcc/11.1  gcc/14.0  openmpi/5.0.8

The output format is defined as a colon-separated list of elements. Supported elements are documented in the corresponding sub-command manual pages.

LIST may also be prefixed by + or - to respectively append elements to or subtract them from the currently configured value. For example, report the variants declared by each modulefile in addition to the default output:

$ module avail -o +variant
------------------- /usr/share/modulefiles ------------------
gcc/8.3  gcc/11.1  gcc/14.0  openmpi/5.0.8{cuda=on,off}

This feature helps avoid fragile text parsing pipelines.

Instead of parsing formatted output:

modules_list=$(module avail | grep -v '^---' \
   | sed 's/(default)//g' | head -n -2 | xargs)

A simpler and more robust approach is:

modules_list=$(module avail -o '')

spider

The module spider sub-command lists all available modulefiles found in enabled modulepaths, including modulepaths recursively added by modulefiles.

Unlike avail, spider explores the full dependency tree created by module use, append-path, or prepend-path instructions.

This command is especially useful with hierarchical module layouts, where some modulefiles only become visible after loading compiler or MPI dependencies.

The spider sub-command accepts the same display and formatting options as avail, including --output, --latest, --default, --json, --indepth, and --no-indepth.

For example, in a hierarchical environment:

$ module avail
------------------- /usr/share/modulefiles/common ------------------
gcc/14.0  intel/25.0

Only compiler modules are initially visible.

The spider sub-command reveals additional modules together with their dependency path:

$ module spider
------------------- /usr/share/modulefiles/common ------------------
gcc/14.0  intel/25.0


---------- /usr/share/modulefiles/intel (via intel/25.0) -----------
intelmpi/25.0

------------ /usr/share/modulefiles/gcc (via gcc/14.0) -------------
openmpi/5.0.8

This output indicates which modules must be loaded before these MPI stacks become available.

Modules caches are automatically used by spider when configured, which significantly improves search performance on large installations.

--latest and --default

The --latest, or -L, and --default, or -d, options restrict the output of the module avail and spider sub-commands.

For example, with the following available modulefiles:

$ module avail
------------------- /usr/share/modulefiles ------------------
gcc/8.3  gcc/11.1  gcc/14.0  intel/24.0  intel/25.0

The --latest option displays only the highest numerically sorted version of each module name.

$ module avail --latest
------------------- /usr/share/modulefiles ------------------
gcc/14.0  intel/25.0

The --default option displays only the default version of each module name. This version is either explicitly defined (as here for gcc) or implicitly the highest one (as for intel).

$ module avail --default
------------------- /usr/share/modulefiles ------------------
gcc/11.1  intel/25.0

These options may also be combined with other display options such as --output or --json.

--indepth and --no-indepth

The --indepth and --no-indepth options control how the module avail and spider sub-commands search for matching modulefiles.

By default, Modules searches recursively and returns all matching modulefiles. This behavior is equivalent to --indepth and can be configured with module config avail_indepth and spider_indepth.

$ module avail
------------------- /usr/share/modulefiles ------------------
intel/24.0  intel/25.0  gcc/8.3  gcc/11.1  gcc/14.0

The --no-indepth option limits results to the depth level expressed by the search query. Modulefiles contained in matching directories are not displayed.

$ module avail --no-indepth
------------------- /usr/share/modulefiles ------------------
intel/  gcc/

--json

The --json, or -j, option displays command results in JSON format.

It is supported by the module avail, list, savelist, search, spider, stashlist, and whatis sub-commands.

JSON output is intended for machine consumption and can be processed directly by tools such as jq or Python scripts.

$ module avail -j | jq .
{
  "/usr/share/modulefiles": {
    "gcc/14.0": {
      "name": "gcc/14.0",
      "type": "modulefile",
      "symbols": [],
      "tags": [],
      "pathname": "/usr/share/modulefiles/gcc/14.0",
      "via": ""
    },
    ...
}

The JSON format is also useful for monitoring, reporting, and integration with external tools.

Manipulating the environment for users

Collections

Collections save and restore sets of loaded modules.

They provide a convenient way to switch between software environments without having to manually load and unload each module.

Collections are managed through several module sub-commands:

Sub-command

Description

save [collection]

Save the current module environment to a collection.

restore [collection]

Restore a collection or collection file.

savelist

List saved collections.

saverm [collection]

Remove a saved collection.

saveshow [collection]

Display information about a collection.

is-saved [collection]

Test whether one or more collections exist.

Collections are stored under the user collection directory, usually $HOME/.module.

The MODULES_COLLECTION_TARGET environment variable may be defined to append a suffix to collection names. This feature is particularly useful on systems sharing a common home directory across multiple clusters.

$ module save
$ module purge
$ module restore

stash commands

Stash collections temporarily save the current module environment and make it easy to switch to another environment.

This feature is similar to the git stash workflow: save the current state, perform other work, then restore the original environment later.

Stash collections are managed through several module sub-commands:

Sub-command

Description

stash

Save the current environment and reset it.

stashpop

Restore and remove a stash collection.

stashrm

Remove a stash collection.

stashshow

Display information about a stash collection.

stashclear

Remove all stash collections.

stashlist

List stash collections.

Save the current environment:

$ module stash

Load a different software stack:

$ module purge
$ module load ...

Restore the original environment:

$ module stashpop

Unlike regular collections, stash collections are intended to be short-lived and are automatically removed when restored with stashpop.

mogui

mogui provides a graphical interface to browse available modules and manage collections.

It offers an alternative to the command line and can be useful for new users discovering a software stack or for users who prefer an interactive interface.

Any environment change made from the GUI, such as loading modules or restoring collections, is applied back to the shell session that launched the application.

The project is available on GitHub: cea-hpc/mogui. It can be installed from PyPI with pip or from Spack.

$ pip install modules-gui

or:

$ spack install py-modules-gui

Then start the graphical interface:

$ mogui
mogui graphical interface

envml

The envml command executes a command in a specific module environment.

It applies the requested module actions, executes the command, then restores the original environment. As a result, the current shell session remains unchanged.

This feature is particularly useful in scripts, tests, and automation workflows where commands must be executed in a controlled software environment.

Supported module actions include:

Action

Description

purge

Purge all loaded modules.

restore=<collection>

Restore a saved collection.

unload=<module>

Unload one or more modules.

switch=<module1>&<module2>

Switch from one module to another.

load=<module>

Load one or more modules.

<module>

Shorthand form of load=<module>.

Multiple actions may be chained with the : separator. When specifying multiple modules for a single action, use the & separator. In some shells, such as Bash, the & character must be escaped or quoted.

For example, execute a command in a clean environment:

$ envml purge -- gcc hello.c

The envml command can simplify scripts by replacing sequences of module operations with a single command.

Instead of:

#!/bin/bash
module purge
module load gcc
gcc hello.c

One can write:

#!/bin/bash
envml purge:gcc -- gcc hello.c

Protected environment variables

The protected_envvars configuration option prevents Modules from modifying selected environment variables. Multiple variables may be specified using the : separator.

This feature is useful to protect critical environment settings from unintended changes.

When a modulefile attempts to modify a protected variable, Modules ignores the modification and emits a warning.

$ module config protected_envvars LD_PRELOAD
$ module load intel
Loading intel/25.0
  WARNING: Modification of protected environment variable LD_PRELOAD ignored

Developing and configuring modulefiles

module edit

The module edit sub-command opens a modulefile in the configured text editor (cf. config editor).

Instead of manually locating a modulefile:

$ vi $(module path appA)

One can directly edit it with:

$ module edit appA

module lint

The module lint sub-command analyzes modulefiles and reports potential issues.

It relies on the Nagelfar Tcl syntax checker to detect syntax errors and common mistakes.

Analyze a specific modulefile:

$ module lint appA

Reported issues may include:

  • Unknown variables

  • Unknown commands

  • Invalid command arguments

  • Tcl syntax errors

source-sh

The source-sh modulefile command evaluates a shell script and tracks the environment changes it performs.

The detected changes are translated into modulefile actions, making it possible to load and unload shell-based environments through Modules.

It is particularly useful to integrate software distributions that provide environment setup scripts such as setup-env.sh, mpivars.sh, or similar rc-provided files.

For example:

#%Module

source-sh bash /opt/spack/share/spack/setup-env.sh

sh-to-mod

The module sh-to-mod sub-command evaluates a shell script and reports the resulting environment changes as modulefile commands.

It can be used to convert existing shell initialization scripts into modulefiles.

For example:

$ module sh-to-mod bash setup-env.sh > setup-env.mod

Tip

Use sh-to-mod when you want to generate and maintain a regular modulefile from an existing shell script.

mod-to-sh

The module mod-to-sh sub-command evaluates one or more modulefiles and reports the resulting environment changes as shell code.

For example:

$ module mod-to-sh bash appA > setup-env.sh

Tip

The mod-to-sh sub-command can be seen as the reverse operation of sh-to-mod.

prereq

The prereq modulefile command declares one or more modules as a requirement of the current modulefile. When the automated module handling mode is enabled (see auto_handling), which is the default, a requirement is automatically loaded if not yet present in the user environment.

Requirements are sometimes expressed with a condition block:

if { ! [ is-loaded appA ] } {
   module load appA
}

This must be avoided: when appA is already loaded, the condition is false and no requirement rule is defined, so Modules is not aware that the current module depends on appA.

Declare the requirement unconditionally instead:

prereq appA

Loading a module declaring this requirement (here appB) automatically loads the required module when missing:

$ module load appB
Loading appB
  Loading requirement: appA

When automated module handling is disabled, a missing requirement is not automatically loaded: an error is reported and the modulefile load fails.

The module load modulefile command equally declares a requirement rule, and it loads the missing required module even when automated module handling is disabled. The two commands also differ when several modules are specified: module load loads them all (logical AND) whereas prereq requires only one of them (logical OR). Multiple prereq commands act as a logical AND.

conflict

The conflict modulefile command declares one or more modules that cannot be loaded together with the current modulefile.

Instead of manually checking for incompatible modules:

if { [ is-loaded appB ] } {
   puts stderr "ERROR: appB conflicts with appA!"
   exit 1
}

Declare the conflict with:

conflict appB

When the conflict_unload configuration option is enabled in addition to the automated module handling mode (see auto_handling), loading a module automatically unloads the conflicting modules found in the user environment:

$ module load appA
Loading appA
  Unloading conflict: appB

When these options are disabled, an error is reported instead and the modulefile load fails.

A modulefile declaring a conflict on its own module name defines a reflexive conflict: only one version of this module can then be loaded at a time.

conflict appA
$ module load appA/2.0
Loading appA/2.0
  Unloading conflict: appA/1.0

Tip

When only one module should be loaded at a time for any given module name, enable the unique_name_loaded configuration option instead of declaring a reflexive conflict in every modulefile. As this option applies to all existing modules, every module name must follow this rule. It is generally the case when only application modules are provided, but may not be if application configurations are also handled through modulefiles.

variant

The variant modulefile command declares variants and their accepted values.

This command is only available inside modulefiles.

Variants allow users to customize the behavior of a modulefile at load time. They follow the same syntax as Spack variants.

Boolean variants are enabled with + and disabled with ~:

#%Module
variant --boolean cuda
$ module load openmpi +cuda

Variants with multiple values are declared by listing the accepted values:

#%Module
variant compiler gcc intel

And selected with the = syntax:

$ module load openmpi compiler=intel

The getvariant modulefile command retrieves the value of a declared variant, allowing the modulefile to adapt its behavior.

For example:

switch -- [getvariant compiler] {
   gcc {
      prereq gcc
   }
   intel {
      prereq intel
   }
}

Configuration option variant_shortcut defines shortcut characters for variants.

For example:

$ module config variant_shortcut compiler=%

This allows users to write:

$ module load openmpi %gcc

Advanced manipulations

Advanced module version specifiers

Advanced module version specifiers provide a concise way to select modulefiles based on their version or declared variants. They can be used with several module sub-commands, including avail, spider, load, and switch.

Version specifications use the @ character:

Specification

Description

module avail cuda@default

Select the default version.

module avail cuda@latest

Select the latest version.

module avail cuda@12:

Select versions greater than or equal to 12.

module avail cuda@:12

Select versions lower than or equal to 12.

module avail cuda@12:13

Select versions between 12 and 13.

Variant specifications may also be used:

Specification

Description

module avail +mpi

Select modules declaring the mpi variant.

module avail cuda=12

Select modules where the cuda variant is set to 12.

module avail +mpi +cuda

Select modules matching both variant requirements.

--timer and --debug

The --timer and --debug, or -D, options help analyze and troubleshoot Modules commands.

They are supported by most module sub-commands.

The --timer option reports the total execution time of a command.

For example:

$ module avail --timer
------------------- /usr/share/modulefiles ------------------
gcc/8.3  gcc/11.1  gcc/14.0  openmpi/5.0.8

TIMER Total execution took 20.045 ms

The --debug, or -D, option displays debugging messages describing the internal execution of the command.

For example:

$ module avail -D
DEBUG setState: cmdline set to 'modulecmd.tcl bash avail -D'
DEBUG setState: shell set to 'bash'
DEBUG setState: subcmd set to 'avail'
DEBUG setConf: verbosity set to 'debug'
...
------------------- /usr/share/modulefiles ------------------
gcc/8.3  gcc/11.1  gcc/14.0  openmpi/5.0.8

The --timer and --debug options may be combined. In this case, regular debug messages are replaced by execution time reports for each internal procedure call.

$ module avail --timer -D
TIMER parseModuleCommandName avail help (0.151 ms)
TIMER isIcase (0.088 ms)
TIMER defineModStartNbProc 1 (0.060 ms)
...
TIMER Total execution took 31.722 ms

For even more detailed debugging information, use -DD.

.modulerc files

A .modulerc file contains Tcl code automatically evaluated by Modules when encountered during a command execution.

Rc files are used to define module aliases, virtual modules, tags, hidden modules, forbidden modules, ...

Several .modulerc files may be evaluated during a single module command.

Depending on the executed sub-command, Modules may evaluate .modulerc files found in different locations, including:

  • MODULERCFILE

  • $HOME/.modulerc

  • Modulepath and modules directories

For example, the following directory hierarchy contains several .modulerc files:

/home/user/.modulerc
modulefiles/
├── .modulerc
├── app/
│   ├── .modulerc
│   └── 1.0
└── mpi/
    ├── .modulerc
    └── openmpi/5.0

Depending on the requested operation, one or more of these files are evaluated automatically.

See Modulecmd startup for details on the startup sequence, rcfile and ignore_user_rc to configure the evaluation of user rc files, and modulerc_extra_vars and modulerc_extra_cmds to extend .modulerc files.

module-tag

The module-tag modulerc command associates one or more tags with modulefiles.

This command is only available inside .modulerc files.

Tags may be used to provide additional information about modulefiles or to modify their behavior.

For example:

module-tag experimental app/2.0

The tag is then reported along the module name in search results:

$ module avail
------------------- /usr/share/modulefiles ------------------
app/1.0  app/2.0 <experimental>

Several predefined tags affect the behavior of Modules:

Tag

Description

keep-loaded

Prevent automatic unloading when unloading dependent modules.

sticky

Prevent unloading unless --force is specified.

super-sticky

Prevent unloading under any circumstances.

For example:

module-tag sticky core

Once loaded, the core module cannot be unloaded, even with the purge sub-command. The sticky tag is rendered with a specific background color in the output.

$ module purge
Unloading core/1.0
  ERROR: Unload of sticky module skipped
$ module list
Currently Loaded Modulefiles:
 1) core/1.0

Sticky modules can help ensure that essential software stacks remain loaded. The behavior of purge with sticky modules can be configured through sticky_purge.

module-hide

The module-hide modulerc command hides modulefiles from module searches and selection.

This command is only available inside .modulerc files.

A hidden module is excluded from regular searches but may still be selected when explicitly referred to by its exact name.

For example:

module-hide app/1.0

Visibility may also be restricted to specific users or groups.

Time-based restrictions can be defined with --after and --before.

For example:

module-hide --after 2027-01-01 app/1.0

See module-hide for additional visibility options, including soft and hard hiding, as well as users and groups restrictions.

module-forbid

The module-forbid modulerc command prevents designated modulefiles from being loaded.

This command is only available inside .modulerc files.

Unlike a hidden module, a forbidden module remains visible in module searches but cannot be loaded.

For example:

module-forbid app/1.0

A custom message may be displayed when a user attempts to load a forbidden module with the --message option.

For example:

module-forbid --message {Please use app/2.0 instead} app/1.0

See module-forbid for additional restriction options, including custom messages, as well as after/before, users and groups restrictions.

module-virtual

The module-virtual modulerc command associates a virtual module name with an existing modulefile.

This command is only available inside .modulerc files.

Several virtual modules may refer to the same modulefile, reducing the number of files required to define similar modules.

For example:

modulefiles/app/
├── .common
└── .modulerc

The .modulerc file may define several virtual versions:

#%Module
module-virtual 1.0 .common
module-virtual 1.2 .common
module-virtual 1.5 .common
module-virtual 2.0 .common
$ module avail
------------------- /usr/share/modulefiles ------------------
app/1.0  app/1.2  app/1.5  app/2.0

All these virtual modules are evaluated using the same .common modulefile. Its behavior can be adapted according to the virtual module name being evaluated.

#%Module

set version [lindex [split [module-info name] /] end]

setenv APP_VERSION $version

Module logger

Modules can log module activity through the logger and logged_events configuration options.

The logger option defines the command used to record log messages.

For example:

$ module config logger "/usr/bin/logger -t modules"

The logged_events option defines which module events are recorded.

Event

Description

requested_cmd

Record module commands requested by users.

requested_eval

Record modulefile evaluations requested by users.

auto_eval

Record modulefile evaluations automatically triggered by Modules.

Multiple events may be specified using the : separator.

For example:

$ module config logged_events requested_cmd:requested_eval

By default, no events are logged.

The logger command can be customized to integrate Modules activity with an existing logging or monitoring infrastructure.