Files
Joseph Doherty e553db6d40 docs: add Authentication, Clustering, JetStream, Monitoring overviews; update existing docs
New files:
- Documentation/Authentication/Overview.md — all 7 auth mechanisms with real source
  snippets (NKey/JWT/username-password/token/TLS mapping), nonce generation, account
  system, permissions, JWT permission templates
- Documentation/Clustering/Overview.md — route TCP handshake, in-process subscription
  propagation, gateway/leaf node stubs, honest gaps list
- Documentation/JetStream/Overview.md — API surface (4 handled subjects), streams,
  consumers, storage (MemStore/FileStore), in-process RAFT, mirror/source, gaps list
- Documentation/Monitoring/Overview.md — all 12 endpoints with real field tables,
  Go compatibility notes

Updated files:
- GettingStarted/Architecture.md — 14-subdirectory tree, real NatsClient/NatsServer
  field snippets, 9 new Go reference rows, Channel write queue design choice
- GettingStarted/Setup.md — xUnit 3, 100 test files grouped by area
- Operations/Overview.md — 99 test files, accurate Program.cs snippet, limitations
  section renamed to "Known Gaps vs Go Reference" with 7 real gaps
- Server/Overview.md — grouped fields, TLS/WS accept path, lame-duck mode, POSIX signals
- Configuration/Overview.md — 14 subsystem option tables, 24-row CLI table, LogOverrides
- Server/Client.md — Channel write queue, 4-task RunAsync, CommandMatrix, real fields

All docs verified against codebase 2026-02-23; 713 tests pass.
2026-02-23 10:14:18 -05:00

7.5 KiB

Setup

This guide covers prerequisites, building, running, and testing the NATS .NET server.

Prerequisites

.NET 10 SDK

The project targets net10.0 with LangVersion preview (configured in Directory.Build.props). Install the .NET 10 preview SDK from https://dotnet.microsoft.com/download.

Verify your installation:

dotnet --version
# Expected: 10.0.x

Go Toolchain (optional)

The Go toolchain is only needed if you want to run the reference server from golang/nats-server/ or execute Go test suites for cross-validation. It is not required for building or testing the .NET port.

go version
# Expected: go1.22 or later

Building

The solution file uses the .slnx format (not .sln). Pass it explicitly if your tooling requires it.

# Build all projects
dotnet build

# Clean and rebuild
dotnet clean && dotnet build

The solution contains three projects:

Project Path
NATS.Server src/NATS.Server/
NATS.Server.Host src/NATS.Server.Host/
NATS.Server.Tests tests/NATS.Server.Tests/

All projects share settings from Directory.Build.props: net10.0 target framework, nullable reference types enabled, warnings treated as errors.


Running

The server executable is NATS.Server.Host. With no arguments it binds to 0.0.0.0:4222.

dotnet run --project src/NATS.Server.Host

CLI Arguments

Flag Alias Type Default Description
-p --port int 4222 TCP port to listen on
-a --addr string 0.0.0.0 Bind address
-n --name string nats-dotnet-<hostname> Server name reported in INFO
# Custom port
dotnet run --project src/NATS.Server.Host -- -p 14222

# Custom address and name
dotnet run --project src/NATS.Server.Host -- -a 127.0.0.1 -p 4222 -n dev-server

The -- separator is required to pass arguments through dotnet run to the application.

Startup log output (Serilog console sink):

[12:00:00 INF] Listening on 0.0.0.0:4222

Testing

# Run all tests
dotnet test

# Run tests with verbose output
dotnet test -v normal

# Run a single test project
dotnet test tests/NATS.Server.Tests

# Run a specific test by name
dotnet test tests/NATS.Server.Tests --filter "FullyQualifiedName~SubListTests"

Test Stack

Package Version Purpose
xunit (xUnit 3) 2.9.3 Test framework
xunit.runner.visualstudio 3.1.4 VS/Rider test runner integration
Shouldly 4.3.0 Assertion library
NSubstitute 5.3.0 Mocking
NATS.Client.Core 2.7.2 Official NATS .NET client for integration tests
coverlet.collector 6.0.4 Code coverage

Do not use FluentAssertions or Moq — the project uses Shouldly and NSubstitute exclusively.

Test Files

The test project contains 100 test files organised by subsystem. Authentication and TLS tests cover token, username/password, NKey, JWT, and OCSP authenticators, account isolation, client permissions, TLS connection wrapping, and TLS rate limiting (AuthProtocolTests.cs, AuthServiceTests.cs, AuthIntegrationTests.cs, AccountIsolationTests.cs, NKeyAuthenticatorTests.cs, JwtAuthenticatorTests.cs, TlsServerTests.cs, TlsHelperTests.cs, TlsConnectionWrapperTests.cs, TlsMapAuthenticatorTests.cs, TlsRateLimiterTests.cs, and related files). JetStream and RAFT tests cover stream and consumer APIs, publish, pull and push consumers, ack and redelivery, retention policies, mirror/source replication, cluster reload, JWT limits, RAFT election, replication, and snapshot catchup (JetStreamStreamApiTests.cs, JetStreamConsumerApiTests.cs, JetStreamPublishTests.cs, JetStreamPullConsumerTests.cs, JetStreamPushConsumerTests.cs, RaftElectionTests.cs, RaftReplicationTests.cs, RaftSnapshotCatchupTests.cs, and related files). Clustering and routing tests cover route handshake, subscription propagation, gateway and leaf node bootstrap, cluster JetStream config, and response routing (RouteHandshakeTests.cs, RouteSubscriptionPropagationTests.cs, GatewayLeafBootstrapTests.cs, ResponseRoutingTests.cs). Monitoring and configuration tests cover config file parsing and reloading, options processing, monitoring endpoints, account stats, server stats, and subject-transform config (MonitorTests.cs, NatsConfParserTests.cs, ConfigReloadTests.cs, ConfigProcessorTests.cs, SubjectTransformTests.cs, and related files). WebSocket tests cover frame read/write, compression, upgrade handshake, origin checking, and integration (WebSocket/WsFrameReadTests.cs, WebSocket/WsFrameWriterTests.cs, WebSocket/WsCompressionTests.cs, WebSocket/WsUpgradeTests.cs, WebSocket/WsIntegrationTests.cs, and related files). Protocol and parser tests cover NatsParser.TryParse for each command type, header parsing, subject matching, and the SubList trie (ParserTests.cs, NatsHeaderParserTests.cs, SubjectMatchTests.cs, SubListTests.cs). Client lifecycle tests cover command dispatch, subscription tracking, write loop, verbose mode, no-responders, trace mode, client flags, and closed-reason handling (ClientTests.cs, WriteLoopTests.cs, VerboseModeTests.cs, ClientFlagsTests.cs, ClientClosedReasonTests.cs, and related files). Integration tests run end-to-end scenarios against a live server instance using NATS.Client.Core (IntegrationTests.cs, AuthIntegrationTests.cs, NKeyIntegrationTests.cs, PermissionIntegrationTests.cs, SubjectTransformIntegrationTests.cs, ConfigIntegrationTests.cs, WebSocket/WsIntegrationTests.cs).


NuGet: Central Package Management

Package versions are defined centrally in Directory.Packages.props. Individual .csproj files reference packages without a Version attribute:

<!-- Directory.Packages.props -->
<PackageVersion Include="Shouldly" Version="4.3.0" />
<PackageVersion Include="NSubstitute" Version="5.3.0" />
<!-- NATS.Server.Tests.csproj -->
<PackageReference Include="Shouldly" />
<PackageReference Include="NSubstitute" />

To add a new dependency: add a <PackageVersion> entry in Directory.Packages.props, then add a <PackageReference> (without Version) in the relevant .csproj.


Logging

The host configures Serilog via Microsoft.Extensions.Logging in Program.cs:

Log.Logger = new LoggerConfiguration()
    .MinimumLevel.Debug()
    .Enrich.FromLogContext()
    .WriteTo.Console(outputTemplate: "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}")
    .CreateLogger();

using var loggerFactory = new Serilog.Extensions.Logging.SerilogLoggerFactory(Log.Logger);
var server = new NatsServer(options, loggerFactory);

NatsServer and NatsClient receive ILoggerFactory and ILogger respectively via constructor injection. The core library (NATS.Server) depends only on Microsoft.Extensions.Logging.Abstractions — it has no direct Serilog dependency. The Serilog packages are wired in NATS.Server.Host.

Per-client loggers are created with a scoped category name that includes the client ID:

var clientLogger = _loggerFactory.CreateLogger($"NATS.Server.NatsClient[{clientId}]");

To adjust log levels at runtime, modify the LoggerConfiguration in Program.cs.