Skip to content

Support StackExchange.Redis 3.x while maintaining 2.x compatibility #656

Description

@imperugo

Context

StackExchange.Redis 3.x is available (latest: 3.0.11). The library currently depends on SE.Redis 2.12.14.

SE.Redis 3.0 is an internal IO rewrite with no intentional API breaking changes — it is described as a "direct mirror" of 2.13.17 but with a new IO core using RESP3 by default. The only behavioral change is that Execute[Async] now enforces AllowAdmin for admin commands. Performance improvements are significant (2x+ on LRANGE workloads).

Problem

Consumers of StackExchange.Redis.Extensions may reference either SE.Redis 2.x or 3.x in their projects. The NuGet dependency resolution behavior creates two scenarios:

  1. We ship with SE.Redis 2.x dependency — consumers using SE.Redis 3.x get it resolved via binding redirect / assembly unification. This works only if 3.x is truly API-compatible (no removed types, no signature changes). If any APIs diverge in a future 3.x minor, this breaks at runtime.

  2. We ship with SE.Redis 3.x dependency — consumers still on 2.x are forced to upgrade, which may not be possible if they depend on 2.x-specific internal behavior or haven't validated 3.x in their infrastructure.

Neither option is safe for all consumers.

Proposed approach

Option A: Widen the version range (preferred if API-compatible)

Since SE.Redis 3.0 has no API changes, update the PackageReference to use a version range that accepts both:

<PackageReference Include="StackExchange.Redis" Version="[2.12.14,)" />

This allows NuGet to resolve either 2.x or 3.x based on what the consumer has in their project. Our code compiles against the 2.x API surface which is a subset of 3.x.

Risks:

  • If a future SE.Redis 3.x release introduces API changes, our library would compile fine (against 2.x) but fail at runtime when 3.x introduces type/method signature changes
  • RESP3 default in 3.x could surface behavioral differences in edge cases (e.g., SUBSCRIBE command responses)

Mitigation:

  • Run our test suite against both SE.Redis 2.12.x and 3.0.x in CI (matrix build)
  • Pin upper bound if needed: [2.12.14, 4.0.0)

Option B: Dual packages

Publish two variants of the Core package:

  • StackExchange.Redis.Extensions.Core → SE.Redis 2.x
  • StackExchange.Redis.Extensions.Core.v3 → SE.Redis 3.x

Pros: explicit, no surprises.
Cons: doubles the package matrix (Core × Serializers × Compressors), maintenance burden is high.

Option C: Major version bump

Release StackExchange.Redis.Extensions 13.x targeting SE.Redis 3.x only. Keep 12.x on SE.Redis 2.x for consumers who can't upgrade.

Pros: clean separation, follows semver.
Cons: forces a major version bump for what is essentially a transparent dependency upgrade; requires maintaining two branches.

Recommended next steps

  1. Run the full test suite against SE.Redis 3.0.11 locally to verify API compatibility
  2. If tests pass, adopt Option A with upper bound [2.12.14, 4.0.0) and add a CI matrix for both versions
  3. Document the supported SE.Redis version range in README
  4. If any test fails, evaluate whether it's a behavioral difference or an actual API break, and fall back to Option C

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions