Squirix 0.1.0 is an early preview of a .NET distributed cache. A typed client SDK talks to a remote server over gRPC; the server owns state, routing, durability, and operational endpoints.
This is the direction I am validating in 0.1.0 — not a claim that every cache must work this way. Embedded designs are fine for many workloads. Squirix targets a different shape: the application stays a client; the server owns the data lifecycle.
The problem with "just a cache library"
A cache library is simple until you ask who owns what. When cache logic runs inside your app process, state, memory pressure, and persistence share the app's lifecycle. That works for local acceleration (IMemoryCache), but gets ambiguous when you need shared state across instances, durability across restarts, independent health/metrics, or cluster routing.
At that point you often have an implicit server with unclear boundaries. Squirix makes the split explicit from day one.
Embedded mode vs client/server mode
Embedded — cache logic in or tightly coupled to the app process: in-memory caches, libraries that hide remote I/O, or a co-located server called via direct references. Low friction; you rarely expect separate health probes or journal compaction on "just a dependency."
Client/server — the app holds no authoritative state. It connects over a wire contract; the server owns placement, mutations, durability, recovery, and admin/metrics endpoints. Redis and most production distributed caches follow this shape.
Squirix 0.1.0 is client/server first:
application -> Squirix client SDK -> Squirix.Server node(s)
Two packages, enforced at build time: squirix (client) and squirix.server (runtime). The server does not reference the client assembly.
You can embed the server in ASP.NET Core via AddSquirixServer / MapSquirixServer, but application access still goes through SquirixClient.ConnectAsync(...) — even in the same process. That is hosting convenience, not embedded cache semantics in the app layer.
Embedded mode is not bad — it optimizes for different goals. Squirix targets shared remote state, server-owned durability, and operability as infrastructure.
Why Squirix chooses client/server first
Reasoning behind the 0.1.0 shape:
-
Operational boundary — deploy, probe, and upgrade cache nodes independently. Health (
/health/live,/health/ready), admin (/admin/whoami,/admin/ring), and Prometheus at/metricslive on the server. -
Server-owned lifecycle — WAL journal, snapshots, compaction, and recovery stay in
squirix.server, not in every application. - Lighter client package — run the server as its own process or container; apps only reference the client SDK.
-
Clustering path — static consistent-hash routing in 0.1.0 is early, but routing and failover can evolve server-side without rewriting
ICache<T>. - Durability isolation — recovery and compaction failures stay out of application request threads while semantics harden.
How this affects the public API
You connect via SquirixClient.ConnectAsync(...) and work with typed ICache<T> and explicit read results (CacheValueResult<T>):
using System.Threading;
using Squirix;
var cancellationToken = CancellationToken.None;
await using var client = await SquirixClient.ConnectAsync(
"http://localhost:5001",
cancellationToken);
var cache = await client.GetCacheAsync<string>("demo", cancellationToken);
await cache.SetAsync("greeting", "hello", cancellationToken: cancellationToken);
var lookup = await cache.GetValueAsync("greeting", cancellationToken);
if (lookup.Found)
Console.WriteLine(lookup.Value);
Production server hosting uses AddSquirixServer / MapSquirixServer. Transport is gRPC (SquirixCache.proto); cache operations, health, and admin routes are also available over HTTP/2 REST.
What exists in Squirix 0.1.0
0.1.0-preview.1, .NET 10 only:
- Client/server split (
squirix+squirix.server) - Typed
ICache<T>— basic KV + expiration - gRPC + HTTP/2 REST cache endpoints
- Per-node journal, snapshots, compaction, recovery
- Health, readiness, admin routes; Prometheus metrics; OpenTelemetry journal tracing
- Static consistent-hash single-owner routing
For local h2c dev: $env:DOTNET_SYSTEM_NET_HTTP_SOCKETSHTTPHANDLER_HTTP2UNENCRYPTEDSUPPORT = "1"
What is still experimental
Early preview — not production-ready. API, wire format, and on-disk layouts may change during 0.x.
Top comments (0)