ValkeyDotNet 1.2.0
dotnet add package ValkeyDotNet --version 1.2.0
NuGet\Install-Package ValkeyDotNet -Version 1.2.0
<PackageReference Include="ValkeyDotNet" Version="1.2.0" />
<PackageVersion Include="ValkeyDotNet" Version="1.2.0" />
<PackageReference Include="ValkeyDotNet" />
paket add ValkeyDotNet --version 1.2.0
#r "nuget: ValkeyDotNet, 1.2.0"
#:package ValkeyDotNet@1.2.0
#addin nuget:?package=ValkeyDotNet&version=1.2.0
#tool nuget:?package=ValkeyDotNet&version=1.2.0
ValkeyDotNet
ValkeyDotNet — a .NET client library for Valkey, written entirely in C# with RESP2, RESP3, TLS, pipelining, and cluster routing.
ValkeyDotNet is an independent open-source project. It is not an official Valkey project and does not imply Valkey endorsement.
Packages
| Package | Description |
|---|---|
ValkeyDotNet |
Managed Valkey client with its own RESP2/RESP3 protocol implementation. |
Status
ValkeyDotNet 1.2.0 is a stable release for standalone Valkey and primary-routed Valkey Cluster workloads. Supported features are implemented and tested; unsupported behavior fails explicitly. See the changelog for release notes.
ValkeyDotNet implements its own managed RESP protocol. The shipping library has zero runtime package dependencies — no Rust core, no native library, no code generation, no third-party NuGet package. It uses only the .NET base class library.
Implemented:
- RESP2 and RESP3, including maps, sets, attributes, push frames, verbatim strings, big numbers, and streamed values
- TCP and TLS, ACL authentication, client naming, and logical database selection
- Binary-safe generic commands, async cancellation, bounded pending work and response parsing, and command pipelining
- Convenience methods for common string, counter, and hash operations
- Concurrent callers multiplexed on one connection with FIFO reply matching
CLUSTER SHARDSdiscovery withCLUSTER SLOTSfallback, CRC16/hash-tag routing, endpoint mapping, boundedMOVED/ASKhandling, and slot-grouped cluster pipelines- Configurable bounded connections per cluster node for head-of-line isolation
- A dedicated Pub/Sub subscriber with bounded binary message streams and opt-in subscription restoration, plus sharded Pub/Sub and a cluster subscriber with opt-in subscription relocation during slot migration and primary failover
- RESP3 client tracking with binary invalidations, NOLOOP, and BCAST/PREFIX
- A standalone connection owner with bounded recovery and explicit retry authorization, structured Lua scripting, and isolated per-operation deadlines
- Opt-in owner metrics and tracing, free of command or payload capture
Not included in 1.2.0: replica reads, cluster-wide scans, Sentinel discovery, and general-purpose pooling. See the connection model for why, and why managed-only for the positioning.
Requirements
- .NET 10 SDK (pinned via
global.json) - C# 14
- A reachable Valkey server (default port 6379). Verified against Valkey 9.1, 8.1, and 7.2 — see compatibility.
Installation
<PackageReference Include="ValkeyDotNet" Version="1.2.0" />
Documentation
Documentation follows Diátaxis. Start at docs/.
- Tutorial: Getting started
- How-to: Connect over TLS · Use a cluster · Pipeline commands · Send any command · Handle errors · Run live integration tests · Publish a release
- Reference:
ValkeyClient·ValkeyClusterClient· Client options · RESP values · Exceptions · Valkey compatibility · Performance baseline - Explanation: Why managed-only · Connection model
Usage
Connect, then use the typed convenience methods:
using ValkeyDotNet;
await using var valkey = await ValkeyClient.ConnectAsync(
new ValkeyClientOptions
{
Host = "localhost",
Port = 6379,
Protocol = ValkeyProtocol.Resp3,
ClientName = "sample-app",
}
);
await valkey.SetStringAsync("greeting", "hello", TimeSpan.FromMinutes(5));
Console.WriteLine(await valkey.GetStringAsync("greeting"));
Every other Valkey command goes through the generic API, which returns the reply losslessly:
var raw = await valkey.ExecuteAsync(new ValkeyCommand("HGETALL", "user:42"));
foreach (var pair in raw.AsMap())
Console.WriteLine($"{pair.Key.AsString()} = {pair.Value.AsString()}");
The generic command API is intentional: new server commands work immediately, while typed helpers can grow without changing the transport or parser.
Cluster routing
await using var cluster = await ValkeyClusterClient.ConnectAsync(
new ValkeyClusterOptions
{
SeedNodes =
[
new ValkeyClientOptions { Host = "valkey-a.example.com", Port = 6379, UseTls = true },
new ValkeyClientOptions { Host = "valkey-b.example.com", Port = 6379, UseTls = true },
],
}
);
await cluster.SetStringAsync("{user:42}:status", "online");
See Use a Valkey Cluster for generic commands and hash tags.
Pipelining
Pipelining sends a contiguous batch without waiting for individual replies:
var replies = await valkey.ExecutePipelineAsync(
[
new ValkeyCommand("SET", "a", "1"),
new ValkeyCommand("INCR", "a"),
new ValkeyCommand("GET", "a"),
]
);
foreach (var reply in replies)
reply.ThrowIfError();
Pipeline errors are returned in place rather than thrown, so the client can drain every reply and preserve protocol synchronization. Check each reply; an unchecked result hides failures.
Security
- TLS is opt-in via
UseTls. Certificate validation uses the platform default unless a callback is explicitly supplied — and a supplied callback replaces platform validation entirely. - Response size (
MaxResponseBytes, 64 MiB), decoded value count (MaxResponseElements, 1 Mi), and nesting depth (MaxNestingDepth, 128) bound the parser so an unexpectedly large or malicious frame cannot exhaust the process. A declared aggregate cardinality is checked against both the element and byte budgets before anything is allocated for it, so an impossible header is rejected on sight rather than acted on. - Commands that would redefine the connection — the subscribe family,
MONITOR,RESET,HELLO,CLIENT REPLY— are rejected before they are written, leaving the connection usable. - Cancellation during active I/O invalidates the connection, because the stream may sit between protocol frames. Reusing it would misattribute replies across callers.
- Passwords are sent only in the Valkey
HELLO ... AUTHhandshake. Use TLS on untrusted networks. RespValue.ToString()is bounded and escaped to printable ASCII, so a reply cannot flood or corrupt a log line.
Build and test
Common tasks are exposed via just (see justfile):
just # list recipes
just ci # format check, build, test
just build
just test
just pack
The equivalent raw commands:
dotnet tool restore
dotnet csharpier check .
dotnet build ValkeyDotNet.slnx
dotnet run --project tests/ValkeyDotNet.Tests
dotnet pack src/ValkeyDotNet -c Release -o artifacts
The solution targets .NET 10 with TreatWarningsAsErrors and AnalysisLevel=latest-all; every
suppressed analyzer rule carries a written justification in the owning .csproj. CSharpier owns all
formatting, including project files.
Live integration tests need a disposable server and are skipped otherwise. dev/docker-compose.yml
provides one container per maintained Valkey line:
just valkey-up # start 9.x, 8.x, 7.x, and an ACL server
just test-live # defaults to 127.0.0.1:6379
just test-matrix # run the suite against every line
just test-cluster # initialize and test a three-primary cluster
just valkey-down
just cluster-down
Run the BenchmarkDotNet performance and allocation suite in Release:
just bench
See the performance baseline for current timing and allocation numbers.
License
Licensed under the MIT License. Copyright (c) 2026 Aleksandr Pavlov.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- No dependencies.
NuGet packages (1)
Showing the top 1 NuGet packages that depend on ValkeyDotNet:
| Package | Downloads |
|---|---|
|
HostLoom.Valkey
Standalone Valkey backend for HostLoom caching and coordination locks over ValkeyDotNet. |
GitHub repositories
This package is not used by any popular GitHub repositories.
Improves connection integrity and resilience: push notifications dispatch through a bounded background queue with DroppedPushCount, server-error and protocol diagnostics are bounded and sanitized, runtime session-changing commands are rejected on shared connections, cluster node connects reserve capacity and no longer inherit caller cancellation or deadlines, ambiguous ASKING failures surface as ValkeyAskingException without replay while keeping the connection usable, and script recovery runs only for exact NOSCRIPT cache-miss messages.