CppModules (C++20)

Modules (C++20)

Since its earliest days, C++ has organized code across translation units using #include and header files — a system inherited almost unchanged from C. C++20 introduces modules as a fundamentally different, compiler-understood alternative, aimed at the compile-time and correctness problems the header system has always carried.
The problem with #include
Traditional pain points of the header system
The preprocessor handles #include by textually pasting the entire contents of a header file into every source file that includes it, every single time. On a large project, the same standard library and project headers get re-parsed thousands of times across different translation units, which is a major contributor to slow C++ build times. Headers also leak: macros defined in one header can silently affect code in a completely unrelated file included afterward, include order can matter in surprising ways, and include guards / #pragma once are a manual, error-prone workaround for the fact that including the same header twice would otherwise redefine everything in it.
export module and import
A module is declared with export module name, and consumed with import name — instead of copy-pasting text, the compiler processes the module once, produces a compact binary interface description, and reuses that description everywhere the module is imported.

A minimal module (math.ixx / math.cppm) and its consumer

CPP
// math.ixx -- the module interface file
export module math;

export int square(int x) {
    return x * x;
}

export int cube(int x) {
    return x * x * x;
}

// -----------------------------------------------------------------
// main.cpp -- consuming the module
import math;
#include <iostream>

int main() {
    std::cout << square(5) << "\n"; // 25
    std::cout << cube(3) << "\n";   // 27
    return 0;
}

Aspect

Headers (#include)

Modules (import)

Processing

Re-parsed textually in every including file

Compiled once into a binary interface, then reused

Macro leakage

Macros can leak across include boundaries

Macros do not leak out of a module by default

Multiple inclusion

Requires include guards / #pragma once

Not an issue -- importing twice is safe by design

Compile times

Grow with repeated header re-parsing

Generally faster on large codebases

Current state of adoption
Modules are still maturing, honestly
Compared to other C++20 features like concepts and ranges, modules support across compilers and — critically — build systems (CMake, Ninja, MSBuild) has taken longer to stabilize, since modules require genuinely new build-graph logic rather than just new compiler syntax. As of the most recent standards, tooling has improved significantly but is still less universally battle-tested than the decades-old header system. If you're evaluating modules for a real project, check that your specific compiler version and build system combination has mature support before committing to them wholesale.
  • The header + #include system is textual, re-parsed repeatedly, and prone to macro leakage and ordering issues.

  • export module declares a module; import consumes it, with no textual copy-pasting involved.

  • Modules are compiled once into a reusable binary interface, which can meaningfully speed up large builds.

  • Modules are a newer, still-maturing feature -- verify your compiler and build system support before adopting them.