Scaling with Redis Backplane
Scale SignalR across multiple servers using a Redis backplane to synchronize messages between instances.
Scaling with Redis Backplane is a free C# Academy lesson on CoddyKit. This is lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the C# Academy learning path, and your progress syncs across the web and the CoddyKit app. The C# Academy course includes 4 lessons in total.
The Multi-Server Problem
When SignalR runs on a single server, clients and the server share memory for connections and groups. Scale to two or more servers and each server only knows about its own connections — a message sent on Server A never reaches clients connected to Server B.
What Is a Backplane?
A backplane is a shared message bus between SignalR server instances. When one server wants to send a message, it publishes to the backplane; all servers receive it and forward it to their local connections.
Adding the Redis Backplane
Install the Microsoft.AspNetCore.SignalR.StackExchangeRedis package and call AddStackExchangeRedis() after AddSignalR().
// dotnet add package Microsoft.AspNetCore.SignalR.StackExchangeRedis
builder.Services.AddSignalR()
.AddStackExchangeRedis("localhost:6379", options =>
{
options.Configuration.ChannelPrefix =
RedisChannel.Literal("myapp"); // namespace your channels
});
// Or from config:
// .AddStackExchangeRedis(builder.Configuration.GetConnectionString("Redis")!);How Redis Pub/Sub Works for SignalR
Each SignalR server subscribes to Redis channels. When server A publishes a message for a group or user, Redis delivers it to all subscribers (servers B, C…), which then forward it to their local connections.
// Server A: client sends message
// Hub on Server A calls:
await Clients.Group("room-42").ReceiveMessage(user, msg);
// Internally SignalR publishes to Redis:
// PUBLISH signalr/myapp/group/room-42 <serialized message>
// Redis delivers to Server B and C
// Both servers find connections in "room-42" and push to themConfiguration Options
Fine-tune the Redis connection for production: TLS, password, connection resilience, and pub/sub channel prefix.
builder.Services.AddSignalR()
.AddStackExchangeRedis(opts =>
{
opts.Configuration = ConfigurationOptions.Parse(
builder.Configuration["Redis:ConnectionString"]!);
opts.Configuration.Password = builder.Configuration["Redis:Password"];
opts.Configuration.Ssl = true;
opts.Configuration.AbortOnConnectFail = false;
opts.Configuration.ConnectRetry = 3;
});Azure SignalR Service
For fully managed scaling, use Azure SignalR Service. It acts as the backplane and connection manager — your app servers become stateless and don't hold WebSocket connections themselves.
// dotnet add package Microsoft.Azure.SignalR
builder.Services.AddSignalR()
.AddAzureSignalR(builder.Configuration["Azure:SignalR:ConnectionString"]!);
// That's it — Azure manages all connections and backplane
// Your server scales to zero when not neededSticky Sessions (Fallback for Non-WebSocket Transport)
When using Server-Sent Events or Long Polling (not WebSockets), the same client must always hit the same server — called sticky sessions. Configure this in your load balancer or reverse proxy.
# Nginx: sticky session config (IP hash)
upstream signalr_servers {
ip_hash; # ensures same client hits same server
server server1:5000;
server server2:5000;
server server3:5000;
}
# Or use cookie-based sticky sessions:
# sticky cookie srv_id expires=1h;
# WebSockets don't need sticky sessions —
# the connection is long-lived on one serverGroups Across Multiple Servers
Group membership is maintained by the backplane. Adding a connection to a group on Server A means Server B knows about it via Redis — transparent to application code.
// This works correctly across servers:
public async Task JoinRoom(string room)
{
// Adds to Redis-backed group
await Groups.AddToGroupAsync(Context.ConnectionId, room);
// Clients.Group sends via Redis to all servers
await Clients.Group(room).UserJoined(Context.User!.Identity!.Name!);
}
// No code changes needed — the Redis backplane handles distributionMonitoring Redis Pub/Sub
Monitor Redis channels to verify SignalR traffic and diagnose issues. Use redis-cli SUBSCRIBE or Redis Insights to observe the message flow.
# redis-cli: monitor all SignalR channels
redis-cli PSUBSCRIBE "myapp*"
# Check active channel subscribers
redis-cli PUBSUB CHANNELS "myapp*"
# Check number of subscribers per channel
redis-cli PUBSUB NUMSUB "myapp/all"Handling Redis Failures
If Redis becomes unavailable, SignalR falls back to local-only mode — messages won't cross servers. Configure retry policies and alerting for Redis connectivity.
builder.Services.AddSignalR()
.AddStackExchangeRedis(opts =>
{
opts.Configuration = ConfigurationOptions.Parse(redisConn);
opts.Configuration.AbortOnConnectFail = false; // don't crash app
opts.Configuration.ConnectRetry = 5;
opts.Configuration.ReconnectRetryPolicy =
new ExponentialRetry(5000, maxDeltaBackoffMilliseconds: 60000);
});Real-World: Scaled Chat Architecture
In production, run 3+ SignalR server instances behind a load balancer, with Redis (or Azure SignalR Service) as the backplane. All state lives in Redis; servers are stateless and disposable.
// Architecture:
// [Browser] -> [Load Balancer (any server, WebSocket)] ->
// [SignalR Server 1] -+
// [SignalR Server 2] -+-> [Redis Pub/Sub] -> all servers
// [SignalR Server 3] -+
// Server code is identical on all instances:
builder.Services.AddSignalR().AddStackExchangeRedis(redisConn);
app.MapHub<ChatHub>("/hubs/chat");
// Scale replicas: kubectl scale deployment chat --replicas=3Quick Check
What problem does a SignalR backplane solve?
Recap: Scaling with Redis Backplane
Key takeaways:
- Without a backplane, messages from one server don't reach clients on other servers
- AddStackExchangeRedis() adds a Redis pub/sub backplane transparently
- Azure SignalR Service provides a fully managed, serverless backplane alternative
- Sticky sessions are required for non-WebSocket transports (SSE, Long Polling)
- Group membership is synchronized across servers via the backplane
- Configure AbortOnConnectFail=false and retry policies for Redis resilience
Learn C# with an AI tutor — free
Write and run real code in your browser, get instant help from a 24/7 AI tutor, and pick up where you left off on the web or in the app.
- Courses
- 93
- Lessons
- 346
Frequently Asked Questions
Is the “Scaling with Redis Backplane” lesson free?
Yes — the full text of “Scaling with Redis Backplane” is free to read here on the web. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the C# Academy course, upgrade to CoddyKit PRO. The C# Academy course includes 4 lessons in total.
What will I learn in “Scaling with Redis Backplane”?
Scale SignalR across multiple servers using a Redis backplane to synchronize messages between instances. You practise C# Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start C# Academy?
No prior experience is required. C# Academy on CoddyKit is structured for beginners through advanced learners, so you can start here or from the beginning and move at your own pace. This is lesson 4 of 4.
How long does the “Scaling with Redis Backplane” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this C# Academy lesson?
Yes. Every C# Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- SignalR Hubs & Connections
- Groups, Users & Connection Management
- Strongly Typed Hubs
- Scaling with Redis Backplane