ValkeyDotNet 1.1.0
dotnet add package ValkeyDotNet --version 1.1.0
NuGet\Install-Package ValkeyDotNet -Version 1.1.0
<PackageReference Include="ValkeyDotNet" Version="1.1.0" />
<PackageVersion Include="ValkeyDotNet" Version="1.1.0" />
<PackageReference Include="ValkeyDotNet" />
paket add ValkeyDotNet --version 1.1.0
#r "nuget: ValkeyDotNet, 1.1.0"
#:package ValkeyDotNet@1.1.0
#addin nuget:?package=ValkeyDotNet&version=1.1.0
#tool nuget:?package=ValkeyDotNet&version=1.1.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.1.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
- 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.1.0: replica reads, cluster-wide scans, Sentinel discovery, general-purpose pooling, and automatic subscription relocation during slot migration. 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.1.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.
Adds a dedicated RESP2/RESP3 Pub/Sub subscriber with optional recovery, sharded Pub/Sub and a cluster subscriber, a standalone RESP3 client-tracking client, a bounded standalone connection owner, structured Lua scripting, isolated per-operation deadlines with explicit delivery status, opt-in owner telemetry, and lower bulk-reply parsing allocations.