Question
What order should C and C++ header files be included in, and what are the reasons for placing one header before another?
For example, should system headers, C++ standard library headers, Boost headers, and project-local headers appear first or last in an include list?
Short Answer
C++ does not require one universal ordering for #include directives. The important rule is that every header should compile with the declarations it directly needs. A consistent project order—often the current module's header first, followed by project, third-party, standard-library, and system headers—makes missing dependencies easier to find and code easier to review.
Concept
#include is handled by the preprocessor before C++ compilation. Conceptually, it copies the included header's contents into the current source file.
That means include order can affect whether a file compiles: a header may accidentally rely on another header having already been included. This is called a hidden or transitive dependency.
For example, std::string is declared by <string>. If a header uses std::string, that header should include <string> itself. It should not rely on some source file including <string> earlier.
// user_profile.h
#pragma once
#include <string> // Direct dependency: this header uses std::string.
struct UserProfile {
std::string name;
};
The exact visual grouping is a project convention, not a C++ language rule. The real goals are:
- Make each header self-contained.
- Make direct dependencies visible.
- Detect missing includes early.
- Keep include lists predictable for readers and tools.
- Follow the existing repository's formatter and style guide.
A common convention in .cpp files is to include the matching header first. If user_profile.cpp starts with #include "user_profile.h", then user_profile.h must compile without being rescued by unrelated earlier includes in the implementation file.
Mental Model
Think of a header as a recipe card. If the recipe says “add flour,” the card must list flour in its own ingredients. It should not assume that someone read a different recipe card first.
Include order is the order in which recipe cards are placed in a stack. A badly written card may appear to work only because an earlier card happened to provide a missing ingredient. Including the current file's own header first is a quick test: does this card bring everything it needs?
Syntax and Examples
Use #include <...> for headers found through configured system or library include paths, and #include "..." for project headers according to your project's conventions.
A typical .cpp include layout is:
#include "user_profile.h" // Matching header for this implementation file
#include "project/logger.h" // Other project headers
#include <boost/optional.hpp> // Third-party library headers
#include <iostream> // C++ standard library headers
#include <string>
#include <sys/types.h> // Platform/system headers, when needed
Another widely used convention places groups in this order:
- Matching header
- C and C++ standard-library headers
- Third-party headers
- Project headers
Either can be valid. What matters is consistency and the dependency rule: every file includes what it directly uses.
For a header, include only what is necessary for declarations in that header:
Step by Step Execution
Consider this fragile code:
// message.h
#pragma once
struct Message {
std::string text;
};
// message.cpp
#include <string>
#include "message.h"
Step by step:
- The preprocessor starts reading
message.cpp. <string>is inserted first, sostd::stringbecomes known.message.his inserted next.Messagecompiles because<string>happened to be included first.- Another source file that includes
message.hwithout including<string>first can fail to compile.
Fix the dependency at its source:
// message.h
#pragma once
#include <string>
{
std::string text;
};
Real World Use Cases
- Application modules:
account.cppincludesaccount.hfirst so the public header is tested in normal builds. - Libraries and SDKs: Public headers explicitly include declarations they expose, so customers can include them safely.
- Cross-platform code: Platform headers may define macros or types, so projects isolate them in a consistent group or wrapper header.
- Third-party integrations: Boost, Qt, or other external headers are grouped separately, making external dependencies easy to identify.
- Build troubleshooting: Reordering includes can reveal a header that depends accidentally on another header's transitive includes.
- Automated formatting: Tools such as
clang-formatcan sort and separate include groups according to repository rules.
Real Codebase Usage
In a production C++ codebase, the first priority is the repository's existing style. Do not reorder a large file just to apply a different personal convention.
Common patterns include:
- Matching header first: In
widget.cpp, write#include "widget.h"before other includes. This validates the public interface independently. - Direct includes: If a header uses
std::unique_ptr, include<memory>in that header. If it usesstd::vector, include<vector>. - Forward declarations when appropriate: A header can forward-declare a class when it only stores a pointer or reference to it. This can reduce coupling and rebuild time.
- Include-what-you-use: Include declarations that the current file needs directly instead of relying on implementation details of other headers.
- Stable grouping: Separate project, third-party, standard-library, and platform headers with blank lines if that is the local convention.
- Tool-enforced sorting: Configure
clang-formator a linter so formatting is repeatable rather than debated during review.
Example with a forward declaration:
// order_service.h
#pragma once
#include <memory>
class Logger;
{
:
;
:
std::shared_ptr<Logger> logger_;
};
Common Mistakes
Relying on an indirect include
Broken header:
// record.h
#pragma once
struct Record {
std::vector<int> values;
};
It may compile in one file only because another included header currently includes <vector>. Fix it directly:
#include <vector>
Including the matching header after unrelated headers
#include <vector>
#include "record.h"
This can hide the missing <vector> in record.h. Prefer this in record.cpp:
#include "record.h"
Then add missing direct dependencies to record.h.
Treating angle brackets and quotes as a dependency rule
Comparisons
| Approach | Best use | Main benefit | Limitation |
|---|---|---|---|
| Matching header first | .cpp implementation files | Finds missing dependencies in the matching header | Does not by itself make all headers self-contained |
| Standard/third-party/project groups | Large projects | Makes dependencies easy to scan | Exact group order is conventional |
| Direct include | A file uses a declaration | Correct, explicit dependency | Can add compilation work if overused |
| Forward declaration | Only pointers/references to a class are exposed | Reduces coupling and included code | Cannot replace a full definition when storing by value or accessing members inline |
| One umbrella/common header | Special controlled cases, such as precompiled headers | May improve build setup in some environments |
Cheat Sheet
- C++ does not prescribe one required include order.
- Follow the repository's style guide and formatter.
- Each header should include what it directly needs.
- In
thing.cpp, commonly put#include "thing.h"first. - Group related categories with blank lines if the project does so.
- Use
<...>and"..."according to project/build conventions; this is mainly about header search paths. - Include
<string>forstd::string,<vector>forstd::vector,<memory>for smart pointers, and so on. - Use a forward declaration only when a complete type is not required in the header.
- Do not depend on transitive includes from standard-library, third-party, or project headers.
- Use
#pragma onceor conventional include guards to prevent repeated inclusion of the same header in one translation unit.
FAQ
Is there an official C++ include order?
No. The C++ language does not require an order such as standard library first or local headers first. Projects choose conventions.
Why include the matching header first in a C++ source file?
It reveals whether that header is self-contained. If the header needs <string> but forgot to include it, the build fails at the right place.
Should a header include every header used by its .cpp file?
No. A header should include only declarations needed by its own public declarations and inline definitions. Implementation-only dependencies belong in the .cpp file.
Can I rely on a standard-library header including another standard-library header?
No. Include the specific standard header for every facility you use. Transitive includes are not a dependable interface.
Should Boost headers go before standard-library headers?
Either order can be acceptable if it matches the project convention. Keep third-party headers grouped separately and make all direct dependencies explicit.
When should I use a forward declaration instead of an include?
Use one when the header only needs to mention a class through a pointer or reference. Include the full definition when storing it by value, inheriting from it, or using members in inline code.
Does #pragma once determine include order?
No. It prevents repeated processing of the same header within one translation unit. It does not provide missing declarations or solve dependency order.
Mini Project
Description
Create a small C++ module with a public header and implementation file. The exercise demonstrates self-contained headers, matching-header-first ordering, and separating interface dependencies from implementation dependencies.
Goal
Build a GreetingService that returns a greeting and compiles without relying on accidental transitive includes.
Requirements
Requirement 1
Keep learning
Related questions
2D Array Loop Order and Cache Performance in C
Learn why swapping nested loops changes 2D array performance in C, using row-major memory layout, cache locality, and practical benchmarks.
Array-to-Pointer Conversion in C and C++ Explained
Learn what array-to-pointer conversion means in C and C++, how array decay works, and how it differs from a pointer to an array.
Building More Fault-Tolerant Embedded C++ Applications for Radiation-Prone ARM Systems
Learn practical C++ and compile-time techniques to reduce soft-error damage in embedded ARM systems exposed to radiation.