Updated on
Pass rollingInterval to the file sink and Serilog starts a new file on that schedule: .WriteTo.File("logs/log.txt", rollingInterval: RollingInterval.Day) produces log20260824.txt, log20260825.txt, and so on.
Two more options decide how long that stays manageable. retainedFileCountLimit caps how many files are kept before the oldest is deleted, and fileSizeLimitBytes with rollOnFileSizeLimit starts a new file when the current one gets too big. Without the second of those, the sink simply stops writing when the limit is hit.
For a more detailed guide on Serilog, refer to the article Serilog Best Practices for Logging in .NET.
Getting Started With Serilog File Sink
First, let’s set up a simple .NET Core Web API application. We’ll need to install the Serilog.Sinks.File NuGet package:
PM> Install-Package Serilog.Sinks.File -Version 7.0.0
To continue, let’s inspect how we can configure rolling file logging with Serilog. We do this in the main file – Program.cs:
Log.Logger = new LoggerConfiguration()
.WriteTo.File("logs/log.txt",
rollingInterval: RollingInterval.Day,
rollOnFileSizeLimit: true)
.CreateLogger();
We configure the rollingInterval parameter to use RollingInterval.Day, ensuring that a new log file is created every day. Additionally, we enable rolling based on file size by setting rollOnFileSizeLimit to true.
Assigning the configuration to Log.Logger is only half of the wiring. The loggers our controllers receive come from the host’s own logging system, so we point that at Serilog as well:
var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllersWithViews(); builder.Host.UseSerilog();
UseSerilog() ships with the Serilog.AspNetCore package, and with no arguments it routes everything through the static Log.Logger we configured above. This is also the step that puts Serilog behind Microsoft’s ILogger API, so nothing in our application code needs to know Serilog is there.
With our configuration in place, let’s navigate into the Controllers directory and then open the HomeController class. There, we can update the code in the Index method:
public IActionResult Index()
{
_logger.LogInformation("TESTING MESSAGE 123..");
return View();
}
The Index method logs an informational-level message through _logger, an ILogger<HomeController> the framework injects into the constructor. That injected logger reaches our file only because of the UseSerilog() call above.
Upon running the application and browsing around, we can expect to observe the creation of a new logs directory at the project root:

The logs directory contains log files named after the roll point, for example, log20260824.txt. Based on our configuration, our app creates a new log file every day. Opening that file, we find our informational entry among the host’s own startup messages:
2026-08-24 00:17:11.927 +02:00 [INF] TESTING MESSAGE 123..
The shape of that line comes from the sink’s default output template, which the outputTemplate parameter replaces when we want a different one. The text after the level is the rendered message, which is worth writing message templates properly for.
What Are the RollingInterval Values in Serilog?
RollingInterval is an enum with six values: Infinite, Year, Month, Day, Hour, and Minute.
Infinite is the default, and Serilog.Sinks.File‘s own enum documents it as “The log file will never roll; no time period information will be appended to the log file name.”
The other five set the boundary at which a new file begins, and each one also sets the filename format. Day produces log20260824.txt; Hour produces log2026082414.txt; Minute adds the minutes. The date is inserted before the extension, so the path we pass is a template rather than a literal filename.
Which one to choose follows from how much a single file grows. Day suits most applications. Hour suits high-volume services where a daily file would grow too large to open comfortably. Month and Year suit low-volume background jobs, where a daily file would mostly be empty.
Rolling Policies in Serilog File Sink
The Serilog.Sinks.File NuGet package supports several rolling policies to control new log file creation. Let’s inspect the ones developers commonly use:
RollingIntervalFileSizeLimitBytesRetainedFileCountLimitRollOnFileSizeLimit
RollingInterval
This policy specifies the time interval after which a new log file should be created. The available options are the six members of the enum: RollingInterval.Infinite, RollingInterval.Year, RollingInterval.Month, RollingInterval.Day, RollingInterval.Hour and RollingInterval.Minute. Infinite is the default, so a file sink configured without this parameter never rolls on a schedule at all.
Please refer to the sample implementation we have in the Getting Started section.
FileSizeLimitBytes
The purpose of setting the FileSizeLimitBytes is to control the maximum size of individual log files:
var log = new LoggerConfiguration()
.WriteTo.File("logs/log.txt",
fileSizeLimitBytes: 524288000,
rollOnFileSizeLimit: true)
.CreateLogger();
By specifying a file size limit using fileSizeLimitBytes parameter and additionally setting rollOnFileSizeLimit parameter to true, we ensure that log files do not grow indefinitely and become too large to manage and consume effectively. The sink’s README states the default plainly: “the file sink limits file size to 1GB by default”. Software developers often find smaller log files easier to search, analyze, and troubleshoot issues using a viewer.
Once we reach the limit of 500 megabytes (524,288,000 bytes), Serilog will create a new log file and continue writing logs into it.
RetainedFileCountLimit
Developers consider this to be an important policy, we use it to specify the maximum number of log files to keep:
var log = new LoggerConfiguration()
.WriteTo.File("logs/log.txt",
retainedFileCountLimit: 21,
rollingInterval: RollingInterval.Day)
.CreateLogger();
With this configuration, we ensure that the old log files will be cleaned up in accordance with retainedFileCountLimit parameter. The default value is 31. The oldest log file will be deleted if the number of files exceeds this limit.
RollOnFileSizeLimit
In regard to the FileSizeLimitBytes rolling policy, setting rollOnFileSizeLimit to true triggers the creation of a new log file when we reach the specified fileSizeLimitBytes.
On the other hand, if we don’t enable file size-based rollover by setting the property to false, the sink stops writing any new events to the file once the limit is reached. This is important to be aware of, as it may result in potential loss of information.
Does the Serilog File Sink Create the Directory?
Yes. The sink creates any missing directories in the path when it opens the first file, so logs/log.txt works without us creating logs first.
That is why a logs folder appears at the project root after the very first run of our sample application: nothing created it but the sink itself.
Two things it does not do. It does not create directories that only appear later in the path through a filename template, and it does not fix a path the process lacks permission to write. Both fail at write time, and by default Serilog fails silently rather than throwing, because a logger that crashes the application on a logging problem is worse than one that drops events.
That silence is worth knowing about. SelfLog is Serilog’s own diagnostic channel, and pointing it at the console is the fastest way to find out why a file never appeared.
Which Rolling Options Should We Configure?
Three, and they work together: an interval, a size limit with rolling enabled, and a retention count.
The interval keeps files navigable: one file per day means finding yesterday’s log is a matter of reading the filename. The size limit stops a single busy day producing a file too large to open. The retention count stops the folder growing forever.
Setting the size limit without rollOnFileSizeLimit: true is the trap. The sink honours the limit by stopping, not by rolling, so logging silently ends partway through the day with no error anywhere.
The sink’s README states the default plainly: “only the most recent 31 files are retained by default (i.e. one long month)”. Retention is worth a second thought in regulated environments. retainedFileCountLimit deletes by count, which means a quiet week and a busy week retain different amounts of history. retainedFileTimeLimit deletes by age, which is usually how a retention policy is written, and when both are set the stricter of the two wins.
| Parameter | Type | Default | What it does |
|---|---|---|---|
path | string | Required | File path; the date or sequence number is inserted before the extension |
rollingInterval | RollingInterval | Infinite | Starts a new file on a schedule |
fileSizeLimitBytes | long? | 1 GB | Maximum size of one file |
rollOnFileSizeLimit | bool | false | Whether to start a new file at the size limit, or stop writing |
retainedFileCountLimit | int? | 31 | How many files to keep before deleting the oldest |
retainedFileTimeLimit | TimeSpan? | None | Deletes files older than this; with a count limit also set, the stricter of the two wins |
shared | bool | false | Allows multiple processes to write to the same file |
buffered | bool | false | Buffers writes; faster, at the cost of losing recent events on a crash |
flushToDiskInterval | TimeSpan? | None | How often a buffered sink flushes |
encoding | Encoding | UTF-8 without BOM | File encoding |
Compressed output is not on that list. The file sink has no gzip parameter of its own; instead it exposes a hooks parameter, and a FileLifecycleHooks implementation can wrap the output stream in OnFileOpened to compress events as they are written.
Conclusion
In this article, we explored how to configure rolling file logging using Serilog.Sinks.File. By utilizing rolling policies such as FileSizeLimitBytes and RetainedFileCountLimit, we can effectively manage log files and ensure that they don’t grow too large or clutter the file system. With Serilog we can flexibly and efficiently handle log files in a .NET application.
How many events reach those files in the first place is a separate lever, and one worth pulling before the retention count: see Serilog’s log levels and minimum-level control. Once the volume is right, logging the class and method name is what makes a large file searchable.
Remember to fine-tune the rolling policies according to the application’s logging needs and disk space constraints.
Tested with .NET 10.0.10.
