Fortran modules
last modified November 14, 2026
A module is a named container for constants, variables and procedures that
other programs and other modules can use. It is a compilation unit of its own:
the compiler processes it once, writes a small file of interface information
next to the object file, and reads that file whenever a later program says
use of the module. That is how the compiler knows the exact type
of every argument in a call that crosses a file boundary. Modules are the
standard way to organise a Fortran project, and this article shows how to
write one, control which names it exports, compile it, and split a large module
into a specification and its implementation.
Defining a module
A module starts with module name and ends with
end module name. Declarations come between the two, and anything
after a contains statement is a module procedure. The module
below keeps one constant, pi, and two functions that use it; it
is saved in a file called geometry.f90.
module geometry
implicit none
real, parameter :: pi = 4.0 * atan(1.0)
contains
function circle_area(radius) result(area)
real, intent(in) :: radius
real :: area
area = pi * radius ** 2
end function circle_area
function circle_circumference(radius) result(c)
real, intent(in) :: radius
real :: c
c = 2.0 * pi * radius
end function circle_circumference
end module geometry
The constant pi is a compile-time value computed from
atan(1.0), and both functions read it by host association.
implicit none in the module applies to everything it contains, so
every procedure in it is protected from accidental new variables. The two
functions are ordinary functions with explicit interfaces, because a module
procedure always has one.
A program uses the module by naming it in a use statement, which
must come before implicit none and before any declarations. The
statement makes every public name of the module visible, so the program can
call circle_area without repeating its declaration.
program m1
use geometry
implicit none
print '(a, f8.3)', 'area: ', circle_area(2.0)
print '(a, f8.3)', 'length: ', circle_circumference(2.0)
end program m1
The program declares no procedure and no constant of its own: everything comes
from geometry. Both calls are checked against the definitions in
the module, including the type and intent of the argument. The area of a
circle with radius 2 is about 12.566, and its circumference is the same number,
because 2 * pi * r and pi * r ** 2 happen to agree at
r = 2.
$ gfortran geometry.f90 m1.f90 -o m1 $ ./m1 area: 12.566 length: 12.566
Importing selected names
A plain use imports every public name, which is convenient in a
small program and noisy in a large one. The only: clause lists the
names that are actually wanted, and a name can be renamed on import with
local = remote. Renaming avoids a clash between two modules that
export the same name, and it lets the caller use a shorter or clearer name.
program m2
use geometry, only: area => circle_area, pi
implicit none
print *, 'pi: ', pi
print *, 'area:', area(1.0)
end program m2
This program imports only the constant and one function, and calls the
function through the local name area. The circumference function
is not visible at all, so a call to it would fail to compile. Renaming does not
create a new procedure: the compiler still calls circle_area, and
the call is checked against the original interface.
$ gfortran geometry.f90 m2.f90 -o m2 $ ./m2 pi: 3.14159274 area: 3.14159274
Public and private names
By default every entity in a module is public. A bare private
statement reverses that default, after which a public :: list
decides what the outside world may see. Keeping the data private and exposing
only the procedures that operate on it prevents a caller from changing the
state behind the module's back. A module variable is created once, before the
program starts, and lives until the program ends; it has the
save attribute implicitly, and all procedures of the module share
the same copy.
module counters
implicit none
private
public :: increment, reset, value
integer :: count = 0
contains
subroutine increment(step)
integer, intent(in) :: step
count = count + step
end subroutine increment
subroutine reset()
count = 0
end subroutine reset
function value() result(n)
integer :: n
n = count
end function value
end module counters
The module exports three procedures and hides the variable count.
Every call to increment adds to the same variable, and
value reports it. The initial value 0 is set once, at
program start, not on every call, which is exactly the behaviour wanted from a
counter.
program m3
use counters
implicit none
call increment(3)
call increment(4)
print *, 'count:', value()
call reset()
print *, 'count:', value()
end program m3
Two calls add 3 and 4, so the first report is 7. reset assigns
zero to the same module variable, and the second report is 0. The program has
no variable called count; the state lives in the module and is
reached only through the three exported procedures.
$ gfortran counters.f90 m3.f90 -o m3 $ ./m3 count: 7 count: 0
Compiling a module
Compiling geometry.f90 produces two files: the object file
geometry.o and the module file geometry.mod. The
.mod file is not a library; it is the compiler's record of the
module's public interface, and the compiler reads it whenever a program uses
the module. A program can therefore only be compiled after the module it
depends on, and the .mod file must be regenerated whenever the
module changes. If it is missing, the compiler stops before checking anything
else.
program nomod
use geometry, only: circle_area
implicit none
print *, 'area:', circle_area(1.0)
end program nomod
This program is correct, but the command below compiles only the program and
never builds the module. The compiler looks for geometry.mod in
the current directory, does not find it, and reports a fatal error instead of
guessing at the interface. Adding geometry.f90 to the same
command, or compiling it first with -c, fixes the problem. The
-J option tells the compiler where to write and look for
.mod files, and a separate build directory usually needs it.
$ gfortran nomod.f90 -o nomod
nomod.f90:2:9:
2 | use geometry, only: circle_area
| 1
Fatal Error: Cannot open module file ‘geometry.mod’ for reading at (1): No such file or directory
compilation terminated.
Submodules
A large module can be split into a parent module that declares the interface
and one or more submodules that contain the bodies. The parent puts the
procedure heading in an interface block, prefixed with
module, and the submodule names its parent in
submodule (parent) child and implements the procedure as a
module function or module subroutine. The module file
of the parent stays small, and the implementation can be recompiled without
recompiling every program that uses it. Submodules are part of Fortran 2008.
module stats
implicit none
private
public :: mean_of_two, spread_of_two
interface
module function mean_of_two(a, b) result(m)
real, intent(in) :: a, b
real :: m
end function mean_of_two
end interface
contains
function spread_of_two(a, b) result(s)
real, intent(in) :: a, b
real :: s
s = abs(a - b)
end function spread_of_two
end module stats
The module declares mean_of_two in an interface block and defines
spread_of_two in the usual way after contains. Both
are public, and both have an explicit interface, but only the second has a body
in this file. The interface block is what a submodule is allowed to complete;
the compiler stores it in stats.mod and waits for the
implementation.
submodule (stats) stats_impl
contains
module function mean_of_two(a, b) result(m)
real, intent(in) :: a, b
real :: m
m = (a + b) / 2.0
end function mean_of_two
end submodule stats_impl
The submodule repeats the heading with the module prefix and
supplies the body. Its name, stats_impl, is local to the build and
does not appear in any use statement. Compiling the parent and
then the submodule produces stats.mod, stats.smod
and stats@stats_impl.smod, and the program below only needs
stats.mod.
program m4
use stats
implicit none
print *, 'mean: ', mean_of_two(3.0, 5.0)
print *, 'spread:', spread_of_two(3.0, 5.0)
end program m4
The mean of 3 and 5 is 4, and their spread is 2. The program cannot tell whether a procedure comes from the parent module or from a submodule; the interface is the same either way. The three commands build the parent, the submodule, and the program in that order, and the linker combines the two object files.
$ gfortran -c stats.f90 $ gfortran -c stats_impl.f90 $ gfortran m4.f90 stats.o stats_impl.o -o m4 $ ./m4 mean: 4.00000000 spread: 2.00000000
A complete example
The last example is a small finance module with two functions and no state. Everything is private by default and only the two functions are exported, so the module's name space stays clean even if it later gains helper procedures. The program asks for the future value of an investment and for the monthly payment of a loan, and formats both answers with two decimals.
module finance
implicit none
private
public :: future_value, monthly_payment
contains
function future_value(principal, rate, years) result(fv)
real, intent(in) :: principal, rate
integer, intent(in) :: years
real :: fv
fv = principal * (1.0 + rate) ** years
end function future_value
function monthly_payment(principal, annual_rate, years) result(p)
real, intent(in) :: principal, annual_rate
integer, intent(in) :: years
real :: p, r
integer :: n
r = annual_rate / 12.0
n = years * 12
p = principal * r / (1.0 - (1.0 + r) ** (-n))
end function monthly_payment
end module finance
future_value compounds a rate once a year, while
monthly_payment converts the annual rate to a monthly one and the
term to months before applying the annuity formula. Each function declares its
own local variables, and the two share nothing but the module name. The
private statement hides a helper if one is added later, without
changing the public interface.
program m5
use finance
implicit none
print '(a, f10.2)', 'future value: ', future_value(1000.0, 0.05, 10)
print '(a, f10.2)', 'monthly payment:', monthly_payment(200000.0, 0.045, 30)
end program m5
A thousand invested at five percent for ten years grows to about 1628.89. A loan of 200,000 at 4.5 percent over thirty years costs about 1013.37 a month. Both calls are checked against the module interfaces, and the program itself contains no arithmetic formula at all.
$ gfortran finance.f90 m5.f90 -o m5 $ ./m5 future value: 1628.89 monthly payment: 1013.37
Next steps
The next article, Fortran arrays, describes the whole-array syntax that module procedures usually operate on. The procedures article shows the interface blocks that a module supplies automatically, and the allocatable arrays article uses modules to return arrays whose size is known only at run time. A module is also the usual home for derived types and generic interfaces, which later articles cover.
Source
Fortran 2018 standard (J3/18-007r1)
The GNU Fortran Compiler manual
Fortran-lang: learning resources
In this article we have defined a module, imported all or some of its names
with use, renamed an imported name, hidden module data behind
private, seen how .mod files make separate
compilation possible, and split an interface from its implementation with a
submodule. The previous article,
Fortran procedures, explains the
subroutines and functions that modules collect.
Author
List all Fortran tutorials.