# How to Use spdlog async_overflow_policy: Block, Overrun_oldest, and Discard_new Explained

> Master spdlog async_overflow_policy block overrun_oldest and discard_new to control asynchronous logger queue behavior. Prevent data loss and optimize performance.

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

---

**The `async_overflow_policy` enum in spdlog controls how asynchronous loggers behave when their internal queue fills up, offering three strategies: `block` (wait for space), `overrun_oldest` (drop oldest messages), and `discard_new` (drop incoming messages).**

When building high-performance applications with **gabime/spdlog**, asynchronous logging prevents your threads from waiting for I/O operations. However, when log production exceeds consumption, the `async_overflow_policy` determines whether your application blocks, drops old data, or discards new messages.

## Understanding the async_overflow_policy Enum

The `async_overflow_policy` enum is defined in [`include/spdlog/async_logger.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/async_logger.h) at lines 22-28. This enum controls the behavior of the thread pool when the message queue reaches capacity.

Each asynchronous logger stores its selected policy in the private member `async_overflow_policy overflow_policy_` (line 68 of the same file). When posting log messages, the logger passes this policy to the thread pool:

```cpp
pool_ptr->post_log(shared_from_this(), msg, overflow_policy_);
pool_ptr->post_flush(shared_from_this(), overflow_policy_);

```

### The Three Policy Options

spdlog provides three distinct strategies for handling queue overflow:

- **`block`**: The calling thread pauses execution until space becomes available in the queue. This guarantees that **all** messages are eventually logged but may increase latency in the producer thread. Use this for critical logs where message loss is unacceptable.

- **`overrun_oldest`**: When the queue fills, the **oldest** message is removed to accommodate the new one. This ensures the most recent information is always preserved, making it ideal for high-throughput scenarios where stale data is less valuable than current entries.

- **`discard_new`**: New messages are **silently discarded** when the queue is full, preserving the existing backlog. Choose this when you must maintain the historical log sequence and can tolerate losing the latest messages.

## Implementation Details in spdlog Source

The actual enforcement of these policies occurs in [`include/spdlog/details/thread_pool-inl.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/details/thread_pool-inl.h) at lines 79-87. Here, the thread pool checks queue capacity before inserting new messages and applies the appropriate action based on the policy passed by the logger.

The thread pool implementation (`spdlog::details::thread_pool`) is shared among all asynchronous loggers, but each logger instance maintains its own `async_overflow_policy` setting. This allows different loggers in the same application to employ different overflow strategies while utilizing the same underlying thread pool.

## Configuring async_overflow_policy in Your Code

You can configure the overflow policy through two primary methods: direct constructor invocation or factory functions.

### Direct Logger Construction

When instantiating `spdlog::async_logger` directly, pass the desired policy as the fourth argument to the constructor:

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

int main() {
    // Create thread pool with queue size 8192
    auto pool = std::make_shared<spdlog::details::thread_pool>(8192, 1);
    auto sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>("app.log", true);
    
    // Block policy (default)
    auto logger_block = std::make_shared<spdlog::async_logger>(
        "block_logger", std::vector<spdlog::sink_ptr>{sink}, pool,
        spdlog::async_overflow_policy::block);
    
    // Overrun_oldest policy
    auto logger_overrun = std::make_shared<spdlog::async_logger>(
        "overrun_logger", std::vector<spdlog::sink_ptr>{sink}, pool,
        spdlog::async_overflow_policy::overrun_oldest);
    
    // Discard_new policy
    auto logger_discard = std::make_shared<spdlog::async_logger>(
        "discard_logger", std::vector<spdlog::sink_ptr>{sink}, pool,
        spdlog::async_overflow_policy::discard_new);
}

```

### Using Factory Aliases

The [`include/spdlog/async.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/async.h) header (lines 34-59) provides convenient factory aliases that embed the policy as a template parameter:

```cpp
// Using async_factory (defaults to block policy)
auto logger_factory = spdlog::async_factory<spdlog::async_overflow_policy::block>::create(
    "factory_logger", sink);

// Using async_factory_nonblock (overrun_oldest)
auto logger_nonblock = spdlog::async_factory_nonblock::create(
    "nonblock_logger", sink);

```

The `async_factory` template defaults to `async_overflow_policy::block`, while `async_factory_nonblock` is explicitly typedef'd to use `async_overflow_policy::overrun_oldest`.

## Performance Implications and Selection Guide

Choosing the appropriate `async_overflow_policy` depends on your application's latency requirements and data criticality:

- **Use `block`** when you require guaranteed message delivery and can tolerate occasional latency spikes in the logging thread. This is essential for audit trails or financial transaction logging.

- **Use `overrun_oldest`** when you need high throughput and recent data is more important than historical completeness. This works well for telemetry or monitoring systems where the latest metric values matter most.

- **Use `discard_new`** when you must preserve the initial state of an operation and cannot afford to lose early diagnostic information, even if it means missing subsequent log entries.

## Summary

- The `async_overflow_policy` enum in [`include/spdlog/async_logger.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/async_logger.h) defines three queue-full behaviors: `block`, `overrun_oldest`, and `discard_new`.
- Each logger maintains its own policy in the `overflow_policy_` member, passed to the thread pool during `post_log()` and `post_flush()` operations.
- Policy enforcement occurs in [`include/spdlog/details/thread_pool-inl.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/details/thread_pool-inl.h) at lines 79-87.
- Configure policies via direct constructor arguments or factory aliases (`async_factory` and `async_factory_nonblock`) defined in [`include/spdlog/async.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/async.h).

## Frequently Asked Questions

### What happens when the spdlog async queue is full?

When the queue fills up, spdlog applies the `async_overflow_policy` specified during logger creation. If set to `block`, the thread waits until space is available. If set to `overrun_oldest`, the oldest message is removed to make room. If set to `discard_new`, the new message is dropped silently.

### Can different loggers use different async_overflow_policy settings?

Yes. While asynchronous loggers share a common `thread_pool` instance, each `spdlog::async_logger` maintains its own `overflow_policy_` member variable. This allows you to create multiple loggers with different policies—for example, a `block` policy for critical error logs and `overrun_oldest` for verbose debug logs—using the same thread pool.

### Where is the async_overflow_policy enforced in spdlog source code?

The policy is enforced in [`include/spdlog/details/thread_pool-inl.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/details/thread_pool-inl.h) at lines 79-87. This implementation checks the queue state before insertion and applies the blocking or discarding logic according to the policy passed from the logger via `post_log()`.

### What is the default async_overflow_policy in spdlog?

The default policy is `block`. When using the `async_factory` template without specifying a policy, or when constructing an `async_logger` without the fourth argument, the system defaults to `async_overflow_policy::block`, ensuring no messages are lost unless explicitly configured otherwise.