Skip to main content
SEMastery
ASP.NETintermediate

Scaling SignalR With a Redis Backplane in ASP.NET Core

Learn how a Redis backplane lets your ASP.NET Core SignalR app run on many servers so every connected user still gets every real-time message.

12 min readUpdated December 16, 2025

Scaling SignalR With a Redis Backplane in ASP.NET Core

Imagine a busy railway station in India. There are many ticket counters open at once. A passenger walks up to Counter 3 and stands there for the whole transaction. Now the station manager wants to make an announcement that every passenger must hear, no matter which counter they are standing at. If the manager only shouts near Counter 3, the people at Counter 1 and Counter 5 will never hear it.

So the station uses a central public-address system. The manager speaks once into a microphone, and every speaker at every counter plays the message. Everyone hears it, no matter where they stand.

A Redis backplane for SignalR is exactly that central PA system. Your app runs on many servers (the counters). A user stays connected to one server. When any server wants to send a real-time message to everyone, it speaks into the shared microphone (Redis), and Redis makes sure every server plays the message to its own connected users.

This article explains why you need this, how it works, and how to set it up step by step.

Why one server is not enough

When you build a chat app, a live scoreboard, or a notifications feed with SignalR, it works perfectly on your laptop. One server holds all the connections. When a message arrives, that one server knows about every connected user and sends to all of them.

But real apps get popular. One server cannot hold thousands of live connections forever. So you add more servers behind a load balancer. This is called scaling out.

Here is the problem. Each server only knows about its own connected users.

Without a backplane, a message only reaches users on the same server.

In the diagram above, Server 1 sends a message to "all users". But "all users" really means "all users I personally know about". User C is connected to Server 2, so User C never gets the message. That is a broken chat app.

We need a way for all servers to share messages. That shared channel is the backplane.

What a backplane actually does

Redis is a fast in-memory store. One of its features is publish/subscribe (often shortened to pub/sub). A server can publish a message to a named channel, and every other server that subscribed to that channel receives a copy.

SignalR uses this pub/sub feature. When you add the Redis backplane:

  • Every app server subscribes to a Redis channel.
  • When any server wants to broadcast, it publishes the message to Redis.
  • Redis sends a copy to every subscribed server.
  • Each server then delivers the message to its own connected users.
With a Redis backplane, every server hears every broadcast and delivers it locally.

Now when Server 1 broadcasts, Redis forwards the message to Server 2 and Server 3 too. Every user gets the message, no matter which server they are on. The "User C misses it" problem is gone.

The journey of one broadcast message

Send
Server
Redis
Servers
Clients

Steps

1

Send

User clicks send; message hits one server

2

Server

That server publishes to Redis

3

Redis

Redis fans the message out to all servers

4

Servers

Each server delivers to its own users

5

Clients

Everyone sees the message in real time

Follow a single chat message from a user click to every other user's screen.

Step 1: Install the package

The backplane lives in a NuGet package called Microsoft.AspNetCore.SignalR.StackExchangeRedis. It uses the popular StackExchange.Redis client under the hood.

Add it to your project:

// Run this in your project folder (terminal / Package Manager)
// dotnet add package Microsoft.AspNetCore.SignalR.StackExchangeRedis
 
// The package version usually matches your .NET version.
// On .NET 10, you would use the 10.x version of the package.

This single package is all you need on the application side. You also need a running Redis server, which we cover near the end.

Step 2: Wire it up in Program.cs

In a minimal ASP.NET Core app, you register SignalR and then chain the Redis backplane onto it. The key line is AddStackExchangeRedis.

var builder = WebApplication.CreateBuilder(args);
 
// Add SignalR, then attach the Redis backplane.
builder.Services
    .AddSignalR()
    .AddStackExchangeRedis(
        builder.Configuration.GetConnectionString("Redis")!);
 
var app = builder.Build();
 
app.MapHub<ChatHub>("/chat");
 
app.Run();

That is the whole change. Your hub code (ChatHub) does not change at all. You write Clients.All.SendAsync(...) exactly as before. SignalR quietly routes the broadcast through Redis for you.

Your connection string lives in appsettings.json:

// appsettings.json
// {
//   "ConnectionStrings": {
//     "Redis": "my-redis-host:6379"
//   }
// }

Step 3: Set a channel prefix (very important)

Here is a small detail that bites many teams. If two different SignalR apps share the same Redis server, and you do not tell them apart, then a broadcast from App A will also reach the users of App B. That is a confusing bug and a possible data leak.

The fix is a channel prefix. It is like writing your app's name on its own private radio frequency so other apps cannot hear you.

using StackExchange.Redis;
 
builder.Services
    .AddSignalR()
    .AddStackExchangeRedis(connectionString, options =>
    {
        // Isolate this app's messages from other apps on the same Redis.
        options.Configuration.ChannelPrefix =
            RedisChannel.Literal("ChatApp");
    });

Give each app a different prefix and they will never cross wires.

Step 4: Keep sticky sessions on

This is the part people forget. The Redis backplane solves message routing between servers. It does not remove the need for sticky sessions (also called session affinity).

A SignalR connection (especially with WebSockets) is a long-lived link. The client must keep talking to the same server for the whole life of that connection. If your load balancer sends the next request to a different server, the connection breaks.

So you need two things working together:

ConcernWho handles it
Keep one client on one serverSticky sessions on the load balancer
Share broadcasts across all serversRedis backplane

Both are required. The backplane is not a replacement for sticky sessions.

Sticky sessions pin a user to a server; the backplane connects the servers together.

How the pieces fit together

Let us zoom out and look at the full shape of a scaled-out SignalR system. You have clients, a load balancer with sticky sessions, several app servers, and one shared Redis that ties them together.

Scaled-out SignalR architecture

Clients
Balancer
Servers
Backplane
Delivery

Steps

1

Clients

Browsers and apps holding live connections

2

Balancer

Sends each user to a server and keeps them there

3

Servers

Many app instances, each with some users

4

Backplane

Redis pub/sub shares every broadcast

5

Delivery

Each server sends to its own connected users

The five layers that make real-time messaging work across many servers.

When Redis is the right choice

The Redis backplane is the recommended scale-out approach for apps you host on your own infrastructure — your own data center, virtual machines, or Kubernetes cluster. It is simple, well-supported, and fast when Redis lives close to your servers.

If your app runs in Azure, Microsoft recommends the Azure SignalR Service instead. It manages all the live connections for you, scales to huge numbers of users, and does not even need sticky sessions because clients connect directly to the service.

Here is a quick comparison to help you choose.

FeatureRedis backplaneAzure SignalR Service
Where it shinesYour own servers / on-premApps hosted in Azure
Sticky sessions neededYesNo
Who holds connectionsYour app serversThe managed service
You run the infraYes (Redis)No (fully managed)
Best forFull control, no cloud lock-inEasy scaling, less ops work

A few real-world tips

Run Redis near your app. For production, a Redis backplane is recommended only when Redis runs in the same data center as your app. If Redis is far away, every message pays a network latency cost and your app feels slow.

Plan for Redis going down. When the Redis server is unavailable, SignalR throws errors saying messages cannot be delivered, and any message sent during the outage is lost. Use a highly available Redis setup such as Redis Sentinel or a managed Redis cluster so a single failure does not stop your app.

Test with more than one server. On your laptop you only run one instance, so the backplane bug never shows up. Spin up two instances locally (different ports) behind a small proxy, open two browser tabs on different instances, and confirm a message in one tab reaches the other. That quick test catches most mistakes.

Here is a tiny hub so you can see that your code stays clean — the backplane is invisible from here:

using Microsoft.AspNetCore.SignalR;
 
public class ChatHub : Hub
{
    // This same call now reaches users on every server,
    // thanks to the Redis backplane. No special code needed.
    public Task SendMessage(string user, string message)
        => Clients.All.SendAsync("ReceiveMessage", user, message);
}

Notice how Clients.All.SendAsync(...) did not change. That is the beauty of the backplane: you add a few lines in Program.cs, and the rest of your real-time code keeps working as it always did.

States your connection moves through

It also helps to picture the life of a single client connection. It connects, stays alive while sticky sessions hold it on one server, may briefly reconnect if the network blips, and finally closes.

The lifecycle of one SignalR client connection in a scaled-out app.

Throughout this whole lifecycle, the backplane keeps doing its quiet job in the background: sharing every broadcast so that no matter which server the client lands on, it still receives every message meant for it.

Common mistakes and how to avoid them

Most problems with a Redis backplane are not deep bugs. They are small setup slips that are easy to fix once you know to look for them. Here are the ones that trip up beginners most often.

The first mistake is forgetting sticky sessions. The app seems to work for a while, then connections randomly drop or fail to start. This happens because the load balancer keeps moving the client between servers. Turn on session affinity and the random failures disappear.

The second mistake is sharing a Redis server without a channel prefix. Two apps work fine on their own, but once they share Redis, users start seeing messages that were never meant for them. Always set a different ChannelPrefix for each app.

The third mistake is putting Redis far away. The app works but feels laggy, with messages arriving a second or two late. Move Redis into the same data center, ideally the same network, as your app servers.

The fourth mistake is assuming Redis never fails. In a demo, one Redis instance is fine. In production, that single instance is a single point of failure. Use a replicated, highly available Redis so one crash does not take your real-time features down with it.

Symptom you seeLikely causeFix
Connections drop at randomNo sticky sessionsEnable session affinity
Users get other apps' messagesShared Redis, no prefixSet a unique ChannelPrefix
Messages arrive slowlyRedis is far from appCo-locate Redis with servers
Real-time stops during an outageSingle Redis instanceUse a highly available Redis

If you keep this short checklist nearby while you set things up, you will sidestep almost every common backplane headache before it ever reaches your users.

Quick recap

  • One SignalR server only knows about its own users, so broadcasts miss users on other servers when you scale out.
  • A Redis backplane uses Redis pub/sub to share every broadcast with all servers, so every user gets every message.
  • Install Microsoft.AspNetCore.SignalR.StackExchangeRedis and call AddStackExchangeRedis(...) after AddSignalR().
  • Set a channel prefix so multiple apps on one Redis server do not mix messages.
  • You still need sticky sessions — the backplane shares messages, but each client must stay on one server.
  • Keep Redis close to your app, and make it highly available, because messages are lost while Redis is down.
  • On your own servers, use the Redis backplane. In Azure, prefer the Azure SignalR Service.

References and further reading

Related Posts