Last modified: June 06, 2026
This article is written in: πΊπΈ
Environment Modules is a tool used to manage software environments from the command line.
It allows users to load, unload, and switch between different software packages and software versions without manually editing shell configuration files every time.
This is especially useful on shared systems, such as high-performance computing clusters, university servers, research machines, and multi-user Linux systems.
For example, one project may need Python 3.8, another may need Python 2.7, and another may need a specific version of GCC or CUDA. Environment Modules makes it possible to switch between these setups safely and quickly.
Without Environment Modules:
User manually edits PATH, LD_LIBRARY_PATH, and other variables
|
v
Easy to make mistakes or create conflicts
With Environment Modules:
User runs module load python/3.8
|
v
Environment variables are adjusted automatically
The main idea is simple:
module load software/version
and later:
module unload software/version
Many programs depend on environment variables.
For example, the shell uses PATH to decide where to search for executable programs. The dynamic linker may use LD_LIBRARY_PATH to find shared libraries. The man command may use MANPATH to find manual pages.
If these variables are not set correctly, software may not run, or the wrong version may run.
Environment Modules solves this by changing the environment only when needed.
User command
|
v
module load gcc/9.3.0
|
v
PATH is updated
LD_LIBRARY_PATH is updated
Other variables are updated
|
v
gcc now points to the selected version
This makes it easier to:
Environment Modules are very common on HPC systems because these systems often have many compilers, MPI libraries, Python versions, CUDA versions, scientific tools, and application stacks installed at the same time.
Environment Modules works by using small configuration files called modulefiles.
A modulefile describes how the environment should change when a software package is loaded.
+-------------+ +------------------+ +----------------------+
| User | | module command | | Modulefile |
| | | | | |
| module load | -----> | Reads modulefile | -----> | Defines environment |
| my_app/1.0 | | | | changes |
+-------------+ +------------------+ +----------------------+
|
v
PATH, LD_LIBRARY_PATH,
MANPATH, and other variables
are updated
For example, loading a module may add a directory to PATH so that a program becomes available:
Before loading module:
PATH=/usr/bin:/bin
After loading my_app/1.0:
PATH=/opt/my_app/1.0/bin:/usr/bin:/bin
The software itself is usually already installed somewhere on the system. The module does not normally install the software. Instead, it tells your shell how to find and use it.
The installation method depends on the Linux distribution.
On many systems, Environment Modules can be installed with the normal package manager.
sudo apt update
sudo apt install environment-modules
The first command updates the package list. The second command installs the Environment Modules package.
On older Red Hat-based systems, you may use yum:
sudo yum install environment-modules
On newer Fedora or Red Hat-based systems, you may use dnf:
sudo dnf install environment-modules
sudo zypper install environment-modules
Sometimes the package manager version is not available or is not the version you need. In that case, Environment Modules can be installed from source.
A source installation usually follows this pattern:
wget https://sourceforge.net/projects/modules/files/Modules/modules-4.7.1/modules-4.7.1.tar.gz
tar -xzf modules-4.7.1.tar.gz
cd modules-4.7.1
wget command downloads the source archive.tar -xzf command extracts the .tar.gz file.cd command moves into the extracted source directory.Then the software can be configured, compiled, and installed:
./configure --prefix=/usr/local/modules
make
sudo make install
./configure command prepares the build and sets the installation location.--prefix=/usr/local/modules option means the software will be installed under:/usr/local/modules
make command compiles the program.sudo make install command installs it.module Command AvailableAfter installing Environment Modules, the shell must be initialized so that the module command becomes available.
For Bash, this is usually done by sourcing an initialization script.
Example:
source /usr/local/modules/init/bash
To make this happen automatically whenever a new Bash shell starts, add the line to ~/.bashrc:
echo "source /usr/local/modules/init/bash" >> ~/.bashrc
Then reload the file:
source ~/.bashrc
The flow looks like this:
Open new shell
|
v
~/.bashrc is read
|
v
Environment Modules init script is sourced
|
v
module command becomes available
If you use another shell, such as Zsh or Tcsh, the initialization file and init script may be different.
For example, with Zsh the line may look like:
source /usr/local/modules/init/zsh
The exact path depends on how Environment Modules was installed.
A modulefile is a small script that describes how to configure the environment for a particular application or version.
Modulefiles are usually written in Tcl.
They commonly modify variables such as:
PATH
LD_LIBRARY_PATH
MANPATH
MODULEPATH
CPATH
LIBRARY_PATH
PKG_CONFIG_PATH
A modulefile can also define custom environment variables, load dependencies, provide help messages, and prevent incompatible modules from being loaded together.
The important idea is:
Software is installed somewhere on the system.
The modulefile tells the shell how to find and use it.
Modulefiles are stored in directories searched by Environment Modules.
The list of directories is controlled by the MODULEPATH environment variable.
Common locations include:
/usr/share/modules/modulefiles
/etc/modulefiles
/usr/local/modulefiles
You can view the current module search path with:
echo "$MODULEPATH"
A typical modulefile layout might look like this:
/etc/modulefiles
βββ python
β βββ 2.7
β βββ 3.6
β βββ 3.8
β βββ .version
βββ gcc
β βββ 8.4.0
β βββ 9.3.0
β βββ 10.2.0
βββ my_app
β βββ 1.0
β βββ 2.1
β βββ 2.2
β βββ default -> 2.1
βββ cuda
β βββ 10.1
β βββ 11.0
β βββ .version
βββ openmpi
β βββ 3.1.4
β βββ 4.0.5
β βββ 4.1.0
βββ cmake
βββ 3.17
βββ 3.18
βββ .version
This layout keeps each application in its own directory.
Inside each application directory, each version has its own modulefile.
For example:
/etc/modulefiles/python/3.8
would be the modulefile for Python 3.8.
This makes it easy to run:
module load python/3.8
Suppose you want to create modulefiles for an application called my_app.
First, create a directory for it:
sudo mkdir -p /usr/share/modules/modulefiles/my_app
The -p option tells mkdir to create parent directories if needed.
Then set permissions so users can access the directory:
sudo chmod 755 /usr/share/modules/modulefiles/my_app
The permission value 755 means:
Owner: read, write, execute
Group: read, execute
Others: read, execute
This is common for shared modulefile directories because normal users should be able to read the modulefiles but not modify them.
A modulefile for my_app version 1.0 might be stored here:
/usr/share/modules/modulefiles/my_app/1.0
To create it:
sudo nano /usr/share/modules/modulefiles/my_app/1.0
Example modulefile:
#%Module1.0#####################################################################
##
## my_app modulefile
##
proc ModulesHelp { } {
puts stderr "This module loads my_app version 1.0"
}
module-whatis "Loads my_app version 1.0"
# Set the installation prefix
set root /opt/my_app/1.0
# Modify environment variables
prepend-path PATH $root/bin
prepend-path LD_LIBRARY_PATH $root/lib
prepend-path MANPATH $root/share/man
# Set custom environment variables
setenv MY_APP_HOME $root
# Prevent multiple my_app versions from being loaded together
conflict my_app
This modulefile says:
my_app is installed in /opt/my_app/1.0
When loaded:
- add /opt/my_app/1.0/bin to PATH
- add /opt/my_app/1.0/lib to LD_LIBRARY_PATH
- add /opt/my_app/1.0/share/man to MANPATH
- define MY_APP_HOME
- prevent conflicting my_app versions
The first line identifies the file as a modulefile:
#%Module1.0
The help procedure defines text shown by module help:
proc ModulesHelp { } {
puts stderr "This module loads my_app version 1.0"
}
The module-whatis command provides a short description:
module-whatis "Loads my_app version 1.0"
Users can see this description with:
module whatis my_app/1.0
The set command defines a Tcl variable:
set root /opt/my_app/1.0
This makes the modulefile easier to maintain. Instead of repeating /opt/my_app/1.0 many times, the file can use $root.
The prepend-path command adds a directory to the front of an environment variable:
prepend-path PATH $root/bin
This means the shell will find programs in $root/bin before checking later directories in PATH.
The setenv command creates or changes an environment variable:
setenv MY_APP_HOME $root
The conflict command prevents incompatible modules from being loaded together:
conflict my_app
This is useful when users should not load multiple versions of the same application at the same time.
MODULEPATHThe MODULEPATH variable tells Environment Modules where to search for modulefiles.
You can think of it like PATH, but for modules instead of executable programs.
PATH tells the shell where to find commands
MODULEPATH tells module where to find modulefiles
To view the current MODULEPATH:
echo "$MODULEPATH"
To temporarily add a modulefile directory:
module use /usr/share/modules/modulefiles
This only affects the current shell session.
To make it permanent, add it to ~/.bashrc:
echo "module use /usr/share/modules/modulefiles" >> ~/.bashrc
source ~/.bashrc
The flow is:
module use /some/module/path
|
v
Directory is added to MODULEPATH
|
v
module avail can now find modules stored there
module CommandsThe module command has several useful subcommands.
The most common ones are:
module avail show available modules
module load load a module
module unload unload a module
module list show currently loaded modules
module show show what a module changes
module help show help for a module
module switch switch from one module to another
module purge unload all modules
To see which modules are available:
module avail
To search for a specific module name:
module avail python
Example output may look like:
---------------- /etc/modulefiles ----------------
python/2.7
python/3.8
python/3.11
This tells you which Python versions can be loaded.
To load a module:
module load my_app
If several versions exist, it is better to specify the version:
module load my_app/1.0
Loading a module updates your environment.
For example:
Before:
my_app command not found
After:
module load my_app/1.0
my_app is available
To load several modules at once:
module load gcc/9.3.0 openmpi/4.0.5 my_app/1.0
The order can matter. For example, an MPI module may depend on a particular compiler module.
To see which modules are currently loaded:
module list
Example output:
Currently Loaded Modulefiles:
1) gcc/9.3.0
2) openmpi/4.0.5
3) my_app/1.0
This is useful when debugging because it shows what environment customizations are active.
To unload a module:
module unload my_app
or:
module unload my_app/1.0
This removes the changes made by the modulefile.
To unload several modules:
module unload gcc openmpi my_app
To see what a module does:
module show my_app/1.0
This displays the environment changes that will happen when the module is loaded.
For example, it may show that the module prepends directories to PATH and LD_LIBRARY_PATH.
This is one of the most useful troubleshooting commands because it helps answer the question:
What exactly does this module change?
Some modulefiles include help messages.
To view help for a module:
module help my_app/1.0
This displays the text defined in the ModulesHelp procedure inside the modulefile.
To replace one version with another, use:
module switch my_app/1.0 my_app/2.0
This unloads my_app/1.0 and loads my_app/2.0.
The result is cleaner than manually unloading one version and loading another.
You can also do it manually:
module unload my_app/1.0
module load my_app/2.0
To unload all currently loaded modules:
module purge
This gives you a clean environment.
However, use it carefully. On some systems, important default modules may be loaded automatically, and module purge may remove them.
A safer workflow is:
module list
module purge
module load gcc/9.3.0 openmpi/4.0.5 my_app/1.0
This lets you see what was loaded before clearing the environment.
If you often use the same group of modules, you can save them as a named collection.
First, load the modules you want:
module load gcc/9.3.0 openmpi/4.0.5 my_app/1.0
Then save the set:
module save my_default_modules
Later, you can restore the same set:
module restore my_default_modules
To list saved module sets:
module savelist
This is useful for returning to a known working environment.
Environment Modules is especially useful for switching between software versions.
Suppose a system has Python 2.7 and Python 3.8 installed in separate locations:
/usr/local/python2.7
/usr/local/python3.8
You can create separate modulefiles for each version.
sudo mkdir -p /etc/modulefiles/python
This directory will hold the Python version modulefiles.
The layout will look like this:
/etc/modulefiles
βββ python
βββ 2.7
βββ 3.8
Create and open the file:
sudo nano /etc/modulefiles/python/2.7
Add:
#%Module1.0
##
## Module for Python 2.7
##
module-whatis "Module for Python 2.7"
prepend-path PATH /usr/local/python2.7/bin
prepend-path LD_LIBRARY_PATH /usr/local/python2.7/lib
conflict python
This modulefile adds Python 2.7 to the front of the shellβs search path.
The conflict python line prevents another Python module from being loaded at the same time.
Create and open the file:
sudo nano /etc/modulefiles/python/3.8
Add:
#%Module1.0
##
## Module for Python 3.8
##
module-whatis "Module for Python 3.8"
prepend-path PATH /usr/local/python3.8/bin
prepend-path LD_LIBRARY_PATH /usr/local/python3.8/lib
conflict python
This modulefile works the same way but points to the Python 3.8 installation.
module load python/2.7
Check the active version:
python --version
Expected result:
Python 2.7.x
First unload Python 2.7:
module unload python/2.7
Then load Python 3.8:
module load python/3.8
Check again:
python --version
Expected result:
Python 3.8.x
The full workflow looks like this:
module load python/2.7
|
v
python command points to Python 2.7
|
v
module unload python/2.7
|
v
module load python/3.8
|
v
python command points to Python 3.8
Administrators can set a default version for a module.
This allows users to run:
module load my_app
instead of:
module load my_app/1.0
There are two common ways to define a default version.
.version FileInside the module directory, create a .version file.
Example:
#%Module1.0
set ModulesVersion "1.0"
This tells Environment Modules that version 1.0 is the default.
Another method is to create a symbolic link named default.
Example:
ln -s 1.0 /usr/share/modules/modulefiles/my_app/default
This creates a link called default that points to version 1.0.
The directory may then look like this:
my_app
βββ 1.0
βββ 2.0
βββ default -> 1.0
If the default needs to change later, the link can be updated.
Modulefiles can include conditional logic because they are written in Tcl.
This allows modulefiles to check the current environment before making changes.
For example, a modulefile may require a specific compiler to be loaded first:
if { [ is-loaded gcc/9.3.0 ] } {
module load dependency_module
} else {
puts stderr "Error: gcc/9.3.0 must be loaded before my_app."
exit 1
}
This means:
If gcc/9.3.0 is loaded:
load dependency_module
Otherwise:
show an error and stop
This is useful when software was compiled with a specific compiler or depends on a specific library stack.
Use explicit versions when loading modules.
Instead of:
module load my_app
prefer:
module load my_app/1.0
This makes your environment more predictable.
Include module commands in scripts and job submission files. For example, an HPC job script might contain:
module purge
module load gcc/9.3.0
module load openmpi/4.0.5
module load my_app/1.0
This makes the job easier to reproduce.
Check loaded modules before running important work:
module list
Inspect unfamiliar modules before loading them:
module show my_app/1.0
Be careful with compiler and MPI combinations. For example, an MPI library built with one compiler may not work correctly with another compiler.
Avoid randomly loading many modules. Too many loaded modules can make the environment confusing and harder to debug.
Use module purge when you need a clean start, but remember that it removes all loaded modules.
module: command not foundThis means the module command is not available in the current shell.
Possible causes:
Environment Modules is not installed
The init script was not sourced
The shell startup file is not configured correctly
For Bash, try:
source /usr/share/modules/init/bash
or, depending on the installation path:
source /usr/local/modules/init/bash
Then test:
module avail
If that works, add the source line to ~/.bashrc.
If you try to load a module and get an error saying it cannot be found, check MODULEPATH.
echo "$MODULEPATH"
Then check available modules:
module avail
If the directory containing your modulefiles is missing, add it:
module use /path/to/modulefiles
Example:
module use /etc/modulefiles
Then try again:
module avail
If a module loads but the program still does not work, inspect the modulefile:
module show my_app/1.0
Check whether paths are correct.
Common mistakes include:
wrong installation path
missing bin directory
missing lib directory
incorrect version number
typo in the modulefile
You can also inspect variables directly:
echo "$PATH"
echo "$LD_LIBRARY_PATH"
echo "$MY_APP_HOME"
If the wrong version of a program runs, check which executable is being used.
Example:
which python
python --version
or:
which gcc
gcc --version
Then check loaded modules:
module list
A wrong version often means another module or manually configured path is taking priority.
If two modules conflict, unload one of them:
module unload my_app/1.0
module load my_app/2.0
Or start clean:
module purge
module load my_app/2.0
If the modulefile includes a conflict rule, Environment Modules may prevent the conflict automatically.
module avail # show available modules
module avail python # search available modules
module load python/3.8 # load a module
module unload python/3.8 # unload a module
module list # show loaded modules
module show python/3.8 # show what a module changes
module help python/3.8 # show module help
module switch old new # switch from one module to another
module purge # unload all modules
module save my_set # save current module set
module restore my_set # restore saved module set
module savelist # list saved module sets
module use /path/to/modules # add a modulefile directory
This example shows a typical user workflow.
module avail python
Example output:
python/2.7
python/3.8
python/3.11
Load Python 3.8:
module load python/3.8
Check the loaded modules:
module list
Check the Python version:
python --version
Switch to another version:
module switch python/3.8 python/3.11
Check again:
python --version
Unload all modules when finished:
module purge
This kind of workflow is common on HPC clusters and shared research systems.
apt install environment-modules for Debian-based systems or yum install environment-modules for CentOS). Explain the purpose of Environment Modules and how they simplify the management of software versions on shared systems./etc/modulefiles for a new application. For example, set up a directory for Python by running sudo mkdir /etc/modulefiles/python. Discuss why /etc/modulefiles is commonly used for storing modulefiles and how it enables centralized module management.sudo touch /etc/modulefiles/python/3.8 to create a modulefile. Briefly describe the structure of modulefile directories and the purpose of organizing applications by version.prepend-path directive to add the bin and lib directories to the PATH and LD_LIBRARY_PATH environment variables, respectively. Include the conflict directive to prevent the loading of incompatible versions simultaneously. Discuss how prepend-path and conflict ensure smooth version management.module load command, and confirm the module is active by checking the output of module list and verifying the applicationβs version (e.g., python --version). Explain how the module load command modifies the user environment to include the application paths defined in the modulefile.module unload command. Verify that the module has been removed by running module list and checking that the applicationβs paths are no longer in your environment. Discuss why itβs essential to unload modules, especially when switching between different versions.module avail command to list all available modules on your system, including the one you created. Explain how the module avail command helps users discover available software and manage multiple applications more effectively.module purge command, and confirm that no modules remain active by checking the output of module list. Discuss the utility of module purge for resetting the environment and ensuring a clean state before loading other modules.
Here are two additional challenges to complete the list, focusing on advanced modulefile customization and persistent module environments:module-whatis to provide a summary and module help to give users more details when they load the module. Discuss how adding metadata improves module discoverability and provides helpful information for users..bashrc or .bash_profile) to automatically load a specific module or set of modules on login. Test this configuration by logging out and back in, then verifying that the module(s) load automatically. Explain the benefits of persistent module environments for frequent users of specific software.