Last modified: June 06, 2026

This article is written in: πŸ‡ΊπŸ‡Έ

Environment Modules

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

Why Environment Modules Are Useful

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.

The Basic Model

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.

Installing Environment Modules

The installation method depends on the Linux distribution.

On many systems, Environment Modules can be installed with the normal package manager.

Debian or Ubuntu

sudo apt update
sudo apt install environment-modules

The first command updates the package list. The second command installs the Environment Modules package.

Red Hat, CentOS, RHEL, or Fedora

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

SUSE or openSUSE

sudo zypper install environment-modules

Installing from Source

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

Then the software can be configured, compiled, and installed:

./configure --prefix=/usr/local/modules
make
sudo make install
/usr/local/modules

Making the module Command Available

After 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.

What Modulefiles Are

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.

Where Modulefiles Are Stored

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

Creating a Modulefile Directory

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.

Writing a Simple Modulefile

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

Understanding the Modulefile Line by Line

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.

Managing MODULEPATH

The 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

Basic module Commands

The 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

Listing Available 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.

Loading Modules

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.

Listing Loaded Modules

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.

Unloading Modules

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

Showing Module Details

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?

Getting Module Help

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.

Switching Between Module Versions

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

Purging All Modules

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.

Saving and Restoring Module Sets

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.

Example: Switching Between Python Versions

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.

Step 1: Create a Python Module Directory

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

Step 2: Create the Python 2.7 Modulefile

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.

Step 3: Create the Python 3.8 Modulefile

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.

Step 4: Load Python 2.7

module load python/2.7

Check the active version:

python --version

Expected result:

Python 2.7.x

Step 5: Switch to Python 3.8

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

Setting Default Module Versions

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.

Using a .version File

Inside 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.

Advanced Modulefile Techniques

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.

Best Practices

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.

Troubleshooting

Problem: module: command not found

This 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.

Problem: Module Not Found

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

Problem: Environment Variables Are Not Set Correctly

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"

Problem: Wrong Software Version Runs

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.

Problem: Conflicting Modules

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.

Useful Command Summary

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

Practical Example Session

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.

Challenges

  1. Install the Environment Modules package on your system using the appropriate package manager command for your operating system (e.g., 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.
  2. Create a directory under /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.
  3. Select a specific version of the application you plan to manage with environment modules (e.g., Python 3.8), and create a modulefile for this version in the directory you set up. For instance, use 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.
  4. Edit the modulefile for the application version you selected, configuring it to load the necessary environment settings. Use the 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.
  5. Load the application module you created using the 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.
  6. Unload the module you just loaded by using the 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.
  7. Use the 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.
  8. Finally, unload all loaded modules using the 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:
  9. Add descriptive metadata to the modulefile, such as a brief description, version information, and any necessary dependencies or prerequisites for the application. Use directives like 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.
  10. Set up a persistent module environment by configuring your shell profile (e.g., .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.