Is Fortran still used? Why we keep it, and how we modernize around it
Key takeaways
- Fortran was number 11 on the TIOBE index in September 2026, and the large weather and climate codes are still 67% to 80% Fortran by GitHub’s count.
- The strongest reason to keep a verified Fortran code is its V&V history; a rewrite resets that history to zero and can add errors the old code never had.
- When C++ or Python must call the code, keep it and expose a C interface with iso_c_binding and bind(C), then bind it with f2py or pybind11.
- A C++ rewrite is worth it when GPU targets or maintenance demand it; the Fortran stays as the test oracle until every new function matches it within a stated tolerance.
Fortran was number 11 on the TIOBE index in September 2026, above Go and PHP, so the short answer to “is Fortran still used” is yes. The longer answer, and the one that matters if you have inherited a Fortran code, is what to do with it. Weather, climate, and defense codes still run on Fortran, and most will keep running on it, because replacing a verified numerical code costs far more than a rewrite estimate admits.
Our default advice is to keep the verified core and modernize around it. Sometimes a C++ rewrite is the right call, and the triggers for each are specific enough to write down.
Modern Fortran is not the FORTRAN 77 you remember
Most engineers who dismiss Fortran picture fixed-form FORTRAN 77 with GOTO and COMMON blocks. The language has moved a long way since. Modern Fortran has modules, derived types, whole-array operations, do concurrent, and coarrays, and the current standard is Fortran 2023, ISO/IEC 1539:2023, published in November 2023.
The compilers are live projects too. GCC’s gfortran and the vendor compilers from Intel (ifx) and NVIDIA (nvfortran) are all in production use. LLVM Flang is the Fortran front end of the LLVM project.
LFortran is an interactive compiler built on LLVM that can run as a Jupyter kernel. It is still in alpha, but its existence tells you where the community’s energy is going.
The big scientific codes still use Fortran as their primary language. GitHub reports these language shares for three public codes in September 2026:
| Code | Domain | Fortran share |
|---|---|---|
| WRF | Weather research and forecasts | 67% |
| E3SM | Earth system (climate) model | 80% |
| ectrans | Spectral transforms of the ECMWF forecast model | 79% |
The reference LAPACK linear algebra library is mostly Fortran as well, and NumPy ships f2py, a tool whose only job is to turn Fortran into Python modules.
SciPy is removing its Fortran, for toolchain reasons
In January 2025 GitHub listed more than 9% of the SciPy repository as Fortran. SciPy now has a stated goal to remove all of its Fortran code, and GitHub no longer lists Fortran for the repository at all [7].
Read the SciPy team’s reasoning before drawing a conclusion, because it is about toolchains rather than numerics. The reasons they give are wheel builds, macOS on Arm, Windows on Arm, and Pyodide. Building a Fortran toolchain on every platform a wheel must support is the burden SciPy chose to drop; the numerical methods themselves held up.
Why Fortran is hard to replace in numerical work
Fortran holds its place in numerical work on performance, stability, backward compatibility, and track record [1, 3].
Performance comes first. The language was designed for arithmetic on arrays, and its aliasing rules tell the compiler more than C or C++ can, so loops optimize with fewer hints from the programmer. A 2023 Los Alamos study judged it “very unlikely” that Fortran codes will perform poorly on future CPUs [2].
Stability is second. The compilers are mature, and standard-conforming code written decades ago compiles and runs on them today without modification.
Backward compatibility is a policy rather than an accident. The Fortran standards committee keeps old code valid; it deletes features rarely, and the major compilers still accept the deleted ones. Compare Python, where PEP 387 lets the core team remove a feature after a deprecation period [4].
A Python code needs regular attention to keep running. A Fortran code can run untouched for decades, which is why so many of them have outlived the people who wrote them.
Track record is the fourth. Aerospace, defense, weather, and climate programs trust Fortran codes that have decades of use behind them, and that trust is earned per code rather than per language.
GPU targets and staffing are where Fortran gives ground. The same Los Alamos study judged it “likely” that Fortran codes will perform poorly on GPUs, and “very likely” that Fortran projects cannot hire enough top computer scientists [2]. Those two are the reasons we recommend a rewrite.
Rewrites reset the V&V history that makes a code trusted
The strongest argument for keeping a Fortran code is the verification and validation (V&V) record behind it. That record belongs to the code as it exists today rather than to the language. In aerospace and defense, a program does not trust a code’s output until the code has been through test campaigns, comparison with measured data, documentation, and review.
That work is long and expensive, and a rewrite in a new language resets it. The new code has to be verified again from the start, and it can carry errors that the old code never had. Two well-known cases show what an error in unverified software costs:
- On February 25, 1991, a Patriot missile battery at Dhahran, Saudi Arabia, failed to intercept a Scud. The GAO traced the failure to a software problem: a rounding error made the system clock drift, and the drift grew with run time. The attack killed 28 Americans [5].
- NASA lost the Mars Climate Orbiter in 1999 because one ground software file gave thruster data in English units while the navigation software expected metric. The spacecraft entered the atmosphere of Mars too low [6].
Both are lessons about what an unverified error costs when the system is real, whatever the language. A verified code that does its job has already paid that price once, and a rewrite asks you to pay it again.
Recent Fortran work: analysis and packaging
Our Fortran work has run from capability analysis to packaging, and it shapes how we advise clients.
One job was a capability analysis of a legacy multi-burn trajectory code. Before anyone decided to keep, wrap, or rewrite it, we read the code and wrote down what it could do and where its limits were. A keep-or-rewrite decision made without that document is a guess dressed up as a plan.
Another was turning a working scientific code into a real package for a customer’s scientist who wanted a standard build. We restructured it as a Fortran Package Manager (fpm) package and added a CI/CD pipeline that builds and deploys it. The scientist got a standard build, and the code got a pipeline to stand on before anyone touched anything else.
Keep the Fortran and give it a C interface
When the Fortran is correct and fast enough, we keep it and put a C interface on it so other languages can call in. The standard mechanism is the iso_c_binding intrinsic module with the bind(C) attribute, part of the language since Fortran 2003; the gfortran interoperability documentation has the full rules.
This minimal example, written for this post, advances each position in a set of state vectors by its velocity times a time step:
module orbit_c_api
use, intrinsic :: iso_c_binding, only: c_int, c_double
implicit none
contains
subroutine drift_states(n, states, dt, status) bind(C, name="drift_states")
integer(c_int), value, intent(in) :: n
real(c_double), intent(inout) :: states(6, n) ! x y z vx vy vz
real(c_double), value, intent(in) :: dt
integer(c_int), intent(out) :: status
states(1:3, :) = states(1:3, :) + dt * states(4:6, :)
status = 0
end subroutine drift_states
end module orbit_c_api
The C prototype for the same function:
/* states points to n blocks of 6 doubles: x y z vx vy vz */
void drift_states(int n, double *states, double dt, int *status);
Most interface errors come from skipping one of these rules:
- Use the interoperable kinds,
c_intandc_double, never plainintegerorreal(8). - Put
valueon scalar arguments that C passes by value. Without it, Fortran expects a pointer where C sent a number. - Fix the symbol name with
bind(C, name=...), so the C side does not depend on compiler name decoration. - Know the array order. Fortran stores arrays column-major and C stores them row-major.
In the example, Fortran states(6, n) has the same memory layout as the C array double states[n][6]. Only the index order is reversed, so Fortran’s states(i, j) is states[j-1][i-1] in C.
A row-major matrix from C or NumPy needs a transpose before it crosses this boundary. An array-order error does not crash. It produces results that are plausible and incorrect, the worst outcome a numerical code can have.
Python bindings through f2py or pybind11
For Python we take one of two paths:
- f2py reads the Fortran source and generates the Python module directly. It is the quickest route for a small, stable interface.
- A C shim and pybind11. The C interface above goes into a C++ extension module. We choose this when the Python API needs classes, error handling, or more than a handful of functions. On the pybind11 side, the argument type
py::array_t<double, py::array::f_style | py::array::forcecast>hands Fortran-order data to the Fortran code.
Rewrite in C++ when GPUs or maintenance demand it
We recommend a rewrite when at least one of these holds:
- The code must run on GPUs, and Fortran GPU support for the target hardware is not good enough.
- The team cannot maintain the Fortran, and the code must change often.
- The code is small enough that a fresh V&V costs less than maintaining two languages indefinitely.
A C++ rewrite in our stack uses Eigen for linear algebra, CMake for the build, and pybind11 for Python access.
The rule that matters most is to keep the Fortran as the test oracle. Every C++ function has to reproduce the Fortran result within a stated tolerance before the Fortran function is retired. That keeps a chain of evidence from the new code back to the old V&V, which is the closest a rewrite can come to inheriting it.
Keep, wrap, or rewrite, side by side
| Option | V&V history | Effort | Good when |
|---|---|---|---|
| Keep | Kept | Low: build, tests, CI | Only Fortran code calls it |
| Wrap | Kept, interface tests added | Medium: C interface and bindings | C++ or Python must call it |
| Rewrite | Must be done again | High: new code and new V&V | GPU work or long-term maintenance requires it |
Recommendations
- Write the capability analysis first. It moves the conversation from “is Fortran old” to “what does this code do, and what does it not do,” which is the question a decision needs.
- Put tests and CI around the code before changing anything else. An fpm package with CI gives a standard build and a safety net for everything after.
- Keep the Fortran as the test oracle, and retire a Fortran function only when its C++ replacement matches it within a stated tolerance.
- Decide a rewrite on a benchmark of the real kernels with the real compilers, never on general language benchmarks.
- Write down the array layout rule before any array crosses the C interface, and test it with known values; an array-order error never announces itself.
References
- V. K. Decyk, C. D. Norton, and H. J. Gardner, “Why Fortran?” Computing in Science & Engineering, 2007. IEEE Xplore
- G. M. Shipman and T. C. Randles, “An evaluation of risks associated with relying on Fortran for mission critical codes for the next 15 years,” Los Alamos National Laboratory, 2023. OSTI
- L. Kedward and others, “The State of Fortran,” Computing in Science & Engineering, 2022. IEEE Xplore
- “PEP 387: Backwards Compatibility Policy,” Python Software Foundation. peps.python.org
- U.S. GAO, “Patriot Missile Defense: Software Problem Led to System Failure at Dhahran, Saudi Arabia,” IMTEC-92-26, 1992. GAO
- NASA, “Mars Climate Orbiter Mishap Investigation Board Phase I Report,” 1999. NASA LLIS
- SciPy, “Detailed SciPy Roadmap: Use of Fortran libraries.” docs.scipy.org
If you have a Fortran code and a decision to make about it, see Scientific and HPC software or schedule a free consultation.