ZetCode

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.

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.

m1.f90
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.

m2.f90
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.

counters.f90
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.

m3.f90
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.

nomod.f90
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.

stats.f90
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.

stats_impl.f90
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.

m4.f90
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.

finance.f90
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.

m5.f90
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

My name is Jan Bodnar, and I am a passionate programmer with extensive programming experience. I have been writing programming articles since 2007. To date, I have authored over 1,400 articles and 8 e-books. I possess more than ten years of experience in teaching programming.

List all Fortran tutorials.