NLog: structured logging for .NET, from nlog.config to AOT
NLog - Flexible and Structured Logging for various .NET Platforms
At a glance
- What is it?
- NLog is a logging platform for .NET with rule-based routing to file, console and extension targets. It suits teams that want their logging policy in configuration rather than in code, and it now targets AOT builds.
- Who is it for?
- Adopt NLog when you want routing rules, layout renderers and structured logging driven by a nlog.config file rather than by code, and when you need a logging path that works under AOT on .NET 6 and later. Do not adopt it if you only need a single console sink and would rather not maintain an XML configuration file, or if you cannot test your own targets and layout renderers against a major version bump.
- Can I use it commercially?
- Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 2 days ago.
- What is it written in?
- Mainly C#, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What NLog solves, and which .NET teams it is for
Application logging usually starts as a Console.WriteLine and ends as a problem. Someone wants file output with daily rotation for production, someone else wants JSON on stdout for the container platform, and a third person wants the same event to reach an HTTP endpoint only when the level is Warning or higher. If those decisions live in code, every change means a rebuild and a redeploy.
NLog puts those decisions in configuration. The README describes it as a free logging platform for .NET with rich log routing and management capabilities, and states that it handles both structured logging and traditional logging from any .NET language. The routing is the part that matters: one log call can fan out to several targets, each with its own layout, filtered by rules you write in config.
The audience is broad by design. The repository topics list netstandard, netstandard20, mono, xamarin, uwp, maui and dotnet, so the same package is meant to cover a console service, an ASP.NET Core API, a desktop application and a mobile app. The README links separate getting-started guides for .NET Framework, ASP.NET Core 6 and a .NET Core console application, which is a fair signal of where the project expects new users to begin. The base NuGet package covers file and console logging; anything else (database, email, HTTPS endpoint) comes from an extension package.
How routing, targets and layout renderers fit together
The mental model has three parts. A logger is what your code calls. A target is a destination: file, console, or something provided by an extension package. A rule connects them, and carries a minimum level and an optional filter.
The data flow is one direction. Your code emits a log event with a level, a message and optional structured properties. NLog walks the rules in order. Each rule matches on the logger name pattern and the level, and if it matches, the event is written to that rule's targets. The same event can match several rules, which is how you send everything to a file while sending only errors to a mail target.
Before an event reaches a target, the target's layout formats it. Layouts are strings containing layout renderers, the placeholders that pull values out of the event and its context. The README points to a published overview of targets and layout renderers, and describes augmenting logs with contextual information and formatting them according to your preference. Structured logging is documented separately in the wiki, and it is what lets a property survive as a field rather than being flattened into the message text.
The trade-off is that this is a configuration-driven design. Reading a log statement in C# tells you nothing about where it ends up; you have to read the config. In a repository with several nlog.config files, one per environment, that indirection is the point. In a small service with one sink, it is overhead.
Installing NLog and writing a first nlog.config
NLog ships as the NuGet package NLog, linked from the README's NuGet badge. The README also links platform-specific getting-started guides and states that the NLog-nuget-package provides everything needed for doing file- and console-logging. After the package is restored, the next step is configuration. NLog is configured through an XML file, and the search data keeps returning to the name nlog.config. The README does not publish a full config example, so the place to get a working one is the getting-started guide for your platform, plus the options list and API reference the README links for the possible options in the config.
Two things are worth knowing before you write that file. The README's targets and layout renderers overview is where the available destination types and format placeholders are enumerated. And the convention is that the file is XML with a targets section and a rules section, where each rule names a logger pattern, a minimum level and the targets to write to. The README does not spell out the element names itself, so treat the wiki guide as the source rather than guessing at schema details.
If the config does not take effect, the README's advice is explicit: check the troubleshooting guide in the wiki before opening an issue, because it usually produces a clear error message that makes the problem obvious.
AOT support and the version boundary it creates
The README states that NLog 6.0 supports AOT, and links a page listing the major changes in that release. The repository topics include aot and aot-compatible, so ahead-of-time compilation is a first-class concern for the project rather than an afterthought.
This matters because logging libraries are a common source of AOT friction. Reflection-based configuration, dynamic layout construction and runtime type inspection all tend to break under trimming or native compilation. A logging library that has been reworked for AOT is telling you its configuration and layout machinery no longer depends on the patterns that the compiler cannot see through.
The boundary is the version. AOT support arrives with 6.0 according to the README, so a project pinned to an earlier major version does not get it by upgrading a patch. That is a real constraint when you are on an older line and cannot move: you either accept the trimming warnings and exclusions, or you plan the upgrade. The README does not document a rollback path for the 6.0 changes, and the major-changes page is the place to look for what moved.
Where NLog is the wrong choice
The clearest case against NLog is a small application with one destination. If everything you log goes to stdout and your container platform collects it, the routing layer is doing nothing for you. You pay for it in an XML file that has to be deployed alongside the binary, kept in sync across environments, and debugged when a rule silently fails to match. Microsoft.Extensions.Logging alone covers that shape of application, and it is already in the default project templates.
The second case is a team that cannot test its configuration. NLog's power comes from rules that are evaluated at runtime, and a rule that matches nothing produces no error, just missing logs. If nobody on the team will write a test that asserts a log event reaches the expected target, the flexibility becomes a liability. The README's own emphasis on the troubleshooting guide is a hint about how often configuration problems come up.
The third case is a heavy dependency on custom extensions. The README documents creating your own custom NLog extensions and links a page listing which extension packages the project maintains. Everything outside that list is somebody else's release cadence. A major version change in NLog can require changes in those packages, and you inherit that coordination work. The README does not promise compatibility for third-party extensions across major versions.
NLog against Microsoft.Extensions.Logging
The honest comparison is not about features but about where the abstraction sits. Microsoft.Extensions.Logging defines an ILogger interface and a provider model, and it is the logging API that ASP.NET Core applications get by default. NLog is a logging implementation with its own configuration format and its own routing engine.
The two are not mutually exclusive. The practical difference is what you configure. With Microsoft.Extensions.Logging alone you set levels and providers through the host builder and appsettings.json, and the set of destinations is whatever providers you have registered. With NLog you write rules that can match on logger name, filter on level, and route one event to several targets with different layouts, all without touching application code. Layout renderers are the other difference: they give you a formatting vocabulary that is specific to NLog and has no direct equivalent in the base Microsoft abstraction.
If your application already uses Microsoft.Extensions.Logging and you only need console output, staying there costs you nothing. If you find yourself writing wrapper classes to fan a single log call out to three destinations with three different formats, that is the point where NLog's rule engine starts paying for itself.
Maintenance, licensing and upgrade cost
The repository is not archived, and the last push was on 2026-09-21. The release history shows v6.2.1 on 2026-09-16, v6.2.0 on 2026-08-16 and v6.1.4 on 2026-07-08, so patch and minor releases are arriving on a monthly-ish cadence within the 6.x line. The README states that major and minor releases are posted on the project news page.
The upgrade cost is concentrated in major versions. The 6.0 release is the one that brought AOT support and came with a documented list of major changes, so moving from 5.x to 6.x is the upgrade to plan rather than the one to run unattended. Minor and patch releases within 6.x are the routine case.
Licensing is straightforward on the surface: the README says NLog is open source under the terms of the BSD license, and the repository carries a BSD-3-Clause licence file. That is a permissive licence, which generally means you can use it in closed-source applications, but the obligations that come with redistribution are set out in LICENSE.txt and this is not legal advice. Check that file, and check the licences of any extension packages separately, because they are separate projects with their own terms.
Editorial conclusion
Adopt NLog when you want routing rules, layout renderers and structured logging driven by a nlog.config file rather than by code, and when you need a logging path that works under AOT on .NET 6 and later. Do not adopt it if you only need a single console sink and would rather not maintain an XML configuration file, or if you cannot test your own targets and layout renderers against a major version bump. Before committing, verify three things on your own build: that your target platform is covered by the extension package you intend to use, that your nlog.config parses under the version you install, and that any custom extension you own still compiles against the current API. The project is not archived and the last push was on 2026-09-21.
Frequently asked questions
Is NLog free to use?
Yes. The README states that NLog is open source software licensed under the terms of the BSD license, and the repository carries a BSD-3-Clause licence file. The extension packages are separate projects, so check their licences individually.
What is NLog?
NLog is a logging platform for .NET. The README describes it as handling both structured logging and traditional logging from any .NET language, with rich log routing and management capabilities, and sending events to targets such as file or console.
How do I install NLog in a .NET project?
The README links the NLog package on NuGet and separate getting-started guides for .NET Framework, ASP.NET Core 6 and .NET Core console applications. The README states that the NLog-nuget-package provides everything needed for doing file- and console-logging.
Does NLog support AOT compilation?
The README states that NLog 6.0 supports AOT, and the repository topics include aot and aot-compatible. AOT support is tied to the 6.0 release, so earlier major versions do not have it.
Where do I get targets beyond file and console in NLog?
The README states that the NLog-nuget-package provides file- and console-logging, and that other output options such as database, email and https-endpoint come from extension packages. It links an overview of targets and layout renderers.
What should I check first if NLog is not writing logs?
The README directs users to the wiki troubleshooting guide before opening an issue, noting that it often produces a clear error message that makes the problem easier to solve. Configuration problems are the usual cause.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/nlog-nlog)