# How to Integrate spdlog into a C++ Project: Header-Only and Compiled Setup Guide

> Integrate spdlog into your C++ project using CMake. Choose compiled or header-only setup and start logging with ease to enhance your application's output.

- Repository: [Gabi Melman/spdlog](https://github.com/gabime/spdlog)
- Tags: how-to-guide
- Published: 2026-07-27

---

**Add spdlog to your project via CMake by linking against `spdlog::spdlog` for compiled mode or `spdlog::spdlog_header_only` for header-only mode, then include `<spdlog/spdlog.h>` to start logging.**

The spdlog library by gabime/spdlog provides a fast, thread-safe logging solution for modern C++ applications. Whether you need a simple console logger or a high-throughput rotating file system, learning how to integrate spdlog into a C++ project is straightforward using either header-only or compiled library approaches.

## Installation Methods: Header-Only vs. Compiled

Spdlog offers two consumption models. The header-only mode exposes all implementation in `include/spdlog/` and requires defining `SPDLOG_HEADER_ONLY` before includes. The compiled mode builds `libspdlog.a` or `spdlog.dll` via the provided [`CMakeLists.txt`](https://github.com/gabime/spdlog/blob/main/CMakeLists.txt), moving heavy template instantiation into a pre-built binary to reduce compile times.

### Header-Only Integration

For header-only usage, copy the `include/spdlog` directory into your project or add the repository as a Git submodule. Define the preprocessor macro to ensure inline definitions are available:

```cpp
#define SPDLOG_HEADER_ONLY
#include <spdlog/spdlog.h>

```

### Compiled Library Integration

For the compiled approach, add spdlog as a subdirectory in your CMake build. This method utilizes the build targets defined in [`CMakeLists.txt`](https://github.com/gabime/spdlog/blob/main/CMakeLists.txt) and links the implementation from [`src/spdlog.cpp`](https://github.com/gabime/spdlog/blob/main/src/spdlog.cpp) and [`src/async.cpp`](https://github.com/gabime/spdlog/blob/main/src/async.cpp):

```cmake
add_subdirectory(spdlog)
target_link_libraries(MyApp PRIVATE spdlog::spdlog)

```

Alternatively, use the header-only CMake target without manually defining macros:

```cmake
target_link_libraries(MyApp PRIVATE spdlog::spdlog_header_only)

```

## Basic Usage with the Default Logger

Once integrated, the fastest way to start logging is through the global default logger, defined in [`include/spdlog/spdlog.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/spdlog.h). This logger writes to stdout with color support and is available immediately without explicit construction:

```cpp
#include <spdlog/spdlog.h>

int main() {
    spdlog::info("Application started");
    spdlog::error("Critical value: {}", 42);
    spdlog::set_level(spdlog::level::debug);
    spdlog::debug("Debug output enabled");
}

```

## Creating Custom Loggers

For production applications, instantiate named **logger** objects managed by the global registry in [`include/spdlog/details/registry.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/details/registry.h). This allows retrieval via `spdlog::get(name)` across translation units.

### Console Loggers

Create colorized console loggers using sinks defined in [`include/spdlog/sinks/stdout_color_sinks.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/sinks/stdout_color_sinks.h):

```cpp
#include <spdlog/sinks/stdout_color_sinks.h>

auto console = spdlog::stdout_color_mt("console");
console->info("Named console logger ready");
spdlog::get("console")->warn("Retrieved from registry");

```

### File and Rotating Loggers

For persistent storage, use the rotating file sink from [`include/spdlog/sinks/rotating_file_sink.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/sinks/rotating_file_sink.h). The implementation in [`src/file_sinks.cpp`](https://github.com/gabime/spdlog/blob/main/src/file_sinks.cpp) handles rotation logic:

```cpp
#include <spdlog/sinks/rotating_file_sink.h>

const std::size_t max_size = 5 * 1024 * 1024; // 5 MiB
const std::size_t max_files = 3;
auto rotating = spdlog::rotating_logger_mt("rotating", "logs/app.txt", max_size, max_files);
rotating->info("Rotating logger initialized");

```

For daily rotation at a specific time, use `spdlog::daily_logger_mt` from the daily file sink header.

## Advanced Configuration Patterns

### Asynchronous Logging

High-throughput applications benefit from the **async logger** implemented in [`include/spdlog/async_logger.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/async_logger.h) and [`src/async.cpp`](https://github.com/gabime/spdlog/blob/main/src/async.cpp). Initialize a thread pool via `spdlog::init_thread_pool()` before creating async loggers:

```cpp
#include <spdlog/async.h>
#include <spdlog/sinks/basic_file_sink.h>

spdlog::init_thread_pool(8192, 1); // queue size, worker threads
auto async_file = spdlog::basic_logger_mt<spdlog::async_factory>("async", "logs/async.txt");
async_file->info("Non-blocking log entry");

```

### Multi-Sink Configuration

Route messages to multiple destinations with distinct formatting by combining sinks from `include/spdlog/sinks/`. Each sink maintains its own log level and pattern:

```cpp
#include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/sinks/basic_file_sink.h>

auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
console_sink->set_level(spdlog::level::warn);

auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("logs/full.txt", true);
file_sink->set_level(spdlog::level::trace);

spdlog::logger multi("multi", {console_sink, file_sink});
multi.info("Visible in file only; console shows warn and above");

```

### Environment-Based Level Configuration

Dynamically adjust verbosity without recompiling by using the configuration helper in [`include/spdlog/cfg/env.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/cfg/env.h):

```cpp
#include <spdlog/cfg/env.h>

spdlog::cfg::load_env_levels(); // Reads SPDLOG_LEVEL environment variable
spdlog::debug("Level controlled by environment");

```

## Summary

- **spdlog** provides both header-only and compiled integration modes via [`CMakeLists.txt`](https://github.com/gabime/spdlog/blob/main/CMakeLists.txt) targets `spdlog::spdlog` and `spdlog::spdlog_header_only`.
- Include `<spdlog/spdlog.h>` to access the default logger or use specific headers like `<spdlog/sinks/rotating_file_sink.h>` for advanced sinks.
- The core **logger** class in [`include/spdlog/logger.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/logger.h) manages sinks and formatting, while [`include/spdlog/details/registry.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/details/registry.h) enables global logger retrieval.
- Enable high-performance logging using the **async logger** with `spdlog::init_thread_pool()` defined in [`src/async.cpp`](https://github.com/gabime/spdlog/blob/main/src/async.cpp).
- Configure runtime behavior through environment variables using `spdlog::cfg::load_env_levels()`.

## Frequently Asked Questions

### What is the difference between header-only and compiled spdlog?

The header-only mode requires adding the `include/` directory to your path and defining `SPDLOG_HEADER_ONLY`, compiling all template code in your translation units. The compiled mode links against `libspdlog.a` built from [`src/spdlog.cpp`](https://github.com/gabime/spdlog/blob/main/src/spdlog.cpp), reducing compilation time for large projects by pre-building the heavy formatting logic.

### How do I change the log level at runtime?

Call `spdlog::set_level(spdlog::level::debug)` on the logger instance or the global default logger. For environment-driven configuration, use `spdlog::cfg::load_env_levels()` from [`include/spdlog/cfg/env.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/cfg/env.h) to parse the `SPDLOG_LEVEL` variable.

### Can I use spdlog in a multi-threaded application?

Yes. All spdlog sinks provided in `include/spdlog/sinks/` are thread-safe by default, utilizing the `_mt` (multi-threaded) suffix. The registry in [`include/spdlog/details/registry.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/details/registry.h) is also thread-safe for registering and retrieving loggers concurrently.

### How do I create a logger that writes to both console and file?

Instantiate multiple sinks, such as `stdout_color_sink_mt` and `basic_file_sink_mt`, and pass them to the `spdlog::logger` constructor. Each sink can have independent log levels and formatting patterns, allowing fine-grained control over output destinations.