# How spdlog File Rotation Works: A Complete Guide to rotating_file_sink

> Learn how spdlog file rotation operates with rotating_file_sink. Discover size-based rotation, cascading renames, and backup management to keep your logs organized and accessible.

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

---

**spdlog implements size-based file rotation through the `rotating_file_sink` class, which monitors `current_size_` and triggers a cascading rename operation via `rotate_()` when logs exceed `max_size`, preserving only `max_files` backups.**

The spdlog library (gabime/spdlog) provides automatic log management through its `rotating_file_sink` implementation. Understanding how spdlog file rotation works is essential for production deployments where disk space management is critical. The mechanism tracks write volume in real-time and automates the archival process through systematic file renaming.

## The rotating_file_sink Architecture

At the core of spdlog file rotation is the **rotating_file_sink** class defined in [`include/spdlog/sinks/rotating_file_sink.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/sinks/rotating_file_sink.h). When instantiated through factory functions like `spdlog::rotating_logger_mt()`, the sink accepts three critical parameters that control rotation behavior:

- **max_size**: The byte threshold that triggers rotation when exceeded
- **max_files**: The maximum number of archived files to retain (oldest files are deleted)
- **rotate_on_open**: Boolean flag to force immediate rotation if the target file already contains data

The sink maintains the current file size in the **`current_size_`** member variable, initialized from `file_helper_.size()` during construction. This counter increments with every log message written to track when the next rotation is required.

## Triggering Rotation: The sink_it_ Method

Rotation occurs during the `sink_it_()` method execution when the accumulated size exceeds the configured threshold. The implementation in [`include/spdlog/sinks/rotating_file_sink-inl.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/sinks/rotating_file_sink-inl.h) (lines 11-17) performs the size check after formatting each log message:

```cpp
// include/spdlog/sinks/rotating_file_sink-inl.h, lines 11-17
if (new_size > max_size_) {
    file_helper_.flush();
    if (file_helper_.size() > 0) {
        rotate_();                     // ← trigger rotation
        new_size = formatted.size();   // reset size after rotation
    }
}

```

The code first flushes the file helper to ensure all data is committed to disk, verifies the file contains data, then invokes the rotation routine. After rotation completes, the size counter resets to the current message size since a fresh file has been opened.

## The Rotation Algorithm: Inside rotate_()

The actual file manipulation occurs in the **`rotate_()`** method (lines 38-66 of [`include/spdlog/sinks/rotating_file_sink-inl.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/sinks/rotating_file_sink-inl.h)). This function implements a cascading rename strategy that shifts existing archives before creating a new active log:

1. **Close the current file** via `file_helper_.close()` to release the file handle
2. **Iterate backwards** from `max_files_` down to 1, renaming [`log.i.txt`](https://github.com/gabime/spdlog/blob/main/log.i.txt) to `log.(i+1).txt`
3. **Handle conflicts** by deleting existing target files before renaming (with retry logic on Windows)
4. **Reopen a fresh file** using `file_helper_.reopen(true)` and reset the size counter

The core implementation appears as follows:

```cpp
// include/spdlog/sinks/rotating_file_sink-inl.h, lines 38-66
for (auto i = max_files_; i > 0; --i) {
    filename_t src = calc_filename(base_filename_, i - 1);
    if (!path_exists(src)) continue;
    filename_t target = calc_filename(base_filename_, i);
    if (!rename_file_(src, target)) { … }
}
file_helper_.reopen(true);

```

The helper function **`calc_filename`** constructs indexed filenames while preserving file extensions (e.g., converting `app.log` to `app.1.log`). If **`max_files_`** is set to 0, the rotation logic is bypassed entirely and the log file grows indefinitely until process termination.

## Creating Rotating Loggers

You instantiate rotating loggers through the factory functions declared in [`include/spdlog/sinks/rotating_file_sink.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/sinks/rotating_file_sink.h) (lines 68-88). The multi-threaded variant provides thread-safe rotation:

```cpp
// Example 1 – Basic rotating logger (multi-threaded)
auto logger = spdlog::rotating_logger_mt(
    "file_logger",               // logger name
    "logs/app.log",              // base filename
    5 * 1024 * 1024,             // 5 MiB max size per file
    3);                          // keep at most 3 rotated files

logger->info("Application started");

```

For single-threaded applications or header-only mode, use the `_st` suffix and enable immediate rotation on startup:

```cpp
// Example 2 – Rotate on startup, single-threaded
spdlog::set_pattern("%Y-%m-%d %H:%M:%S.%e %l %v");
auto logger = spdlog::rotating_logger_st(
    "daily", "logs/daily.log", 10 * 1024 * 1024, 5, true);
logger->warn("Rotated because file existed from previous run");

```

These factories abstract the `rotating_file_sink` construction while exposing the same configuration parameters.

## Key Source Files

The complete rotation mechanism spans four primary files in the gabime/spdlog repository:

- **[`include/spdlog/sinks/rotating_file_sink.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/sinks/rotating_file_sink.h)**: Declares the `rotating_file_sink` template class and factory helpers
- **[`include/spdlog/sinks/rotating_file_sink-inl.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/sinks/rotating_file_sink-inl.h)**: Implements `rotate_()`, `sink_it_()`, and size tracking logic
- **[`include/spdlog/details/file_helper.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/details/file_helper.h)**: Provides the `file_helper` class for low-level file I/O abstraction
- **[`include/spdlog/details/file_helper-inl.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/details/file_helper-inl.h)**: Contains platform-specific file operations including rename and size queries

## Summary

- **spdlog file rotation** is implemented via the `rotating_file_sink` class using size-based triggers
- The **`current_size_`** variable tracks cumulative bytes written, checked against **`max_size_`** on every log operation
- When thresholds are exceeded, **`rotate_()`** performs a cascading rename of archived files from `N` to `N+1`
- The system retains only **`max_files`** archives, deleting older logs automatically
- Factory functions **`rotating_logger_mt`** and **`rotating_logger_st`** provide convenient initialization for multi-threaded and single-threaded contexts

## Frequently Asked Questions

### What happens if max_files is set to 0 in spdlog?

When `max_files` is 0, spdlog disables rotation entirely. The `rotate_()` function will not perform any file renaming operations, allowing the log file to grow without bounds until the process terminates or the filesystem fills.

### How does spdlog handle file renaming conflicts during rotation?

The `rotate_()` method first checks if the target filename exists using `path_exists()`, then deletes it via `rename_file_()` before performing the rename. On Windows systems where file locks may cause transient failures, the implementation includes retry logic with brief sleep intervals to handle high-frequency rotation scenarios.

### What is the difference between rotating_logger_mt and rotating_logger_st?

**`rotating_logger_mt`** creates a multi-threaded logger where the sink uses mutex locking to prevent concurrent rotation operations, suitable for applications logging from multiple threads. **`rotating_logger_st`** omits locking overhead for single-threaded applications, providing better performance when thread safety is not required.

### Can spdlog rotate logs based on time instead of file size?

The `rotating_file_sink` specifically implements size-based rotation as described. For time-based rotation (daily, hourly), spdlog provides a separate **`daily_file_sink`** class in [`include/spdlog/sinks/daily_file_sink.h`](https://github.com/gabime/spdlog/blob/main/include/spdlog/sinks/daily_file_sink.h) that triggers rotation at specified time intervals rather than file size thresholds.