Session persistence, often called "sticky sessions," means your load balancer will send a user back to the exact same backend server for their entire session. This sounds simple, but the most surprising thing about it is how often it breaks and how many different ways it can fail.

Let’s see it in action. Imagine a simple web app with two backend servers, app-01 and app-02. A user hits the load balancer.

# User's browser makes a request to the load balancer IP
curl http://loadbalancer.example.com/

The load balancer, let’s say it’s an Nginx instance, decides to send this first request to app-01.

# Nginx config snippet
upstream backend {
    server app-01.internal:80;
    server app-02.internal:80;

    # This is the key for sticky sessions
    sticky cookie SERVERID expires=1h path=/;
}

server {
    listen 80;
    server_name loadbalancer.example.com;

    location / {
        proxy_pass http://backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Here, sticky cookie SERVERID expires=1h path=/; tells Nginx to set a cookie named SERVERID in the user’s browser. This cookie will contain an identifier for the backend server.

Now, when the user’s browser makes a subsequent request, it will send that SERVERID cookie back to the load balancer.

# User's browser sends the cookie back
# (This is what happens behind the scenes, not something you type)
curl -b "SERVERID=app-01" http://loadbalancer.example.com/

Nginx sees the SERVERID=app-01 cookie and says, "Aha! This user belongs to app-01," and forwards the request directly to app-01 without even considering app-02. This ensures that all subsequent requests from this user’s browser hit app-01 for the next hour, or until the cookie expires.

Why would you even want this?

The primary reason is stateful applications. If your application stores session data locally on the backend server (e.g., user login status, shopping cart contents), then that data is only available on that specific server. If the user is bounced to a different server, their session data is lost, and they’ll appear to be logged out or have an empty cart. Sticky sessions guarantee the user stays with their data.

How it works internally:

The load balancer intercepts incoming requests. If it’s a new request (no session cookie from this load balancer present), it selects a backend server based on its load balancing algorithm (e.g., round-robin, least connections). Then, it generates a unique identifier for that chosen server and instructs the user’s browser to store this identifier in a cookie. For subsequent requests, the load balancer inspects the incoming cookies. If it finds a valid session cookie matching a known backend server, it directs the request to that server. If the cookie is missing or invalid, it repeats the process of selecting a server and setting a new cookie.

The expires=1h part means the cookie will live for one hour. After that, the user will be treated as a new user and assigned a server again. path=/ means the cookie is valid for the entire website.

The most common alternative to cookie-based persistence is IP address-based persistence. In this model, the load balancer remembers which backend server to send requests to based on the client’s source IP address. This is simpler but has a significant drawback: if multiple users are behind a single NAT gateway (like in many corporate networks or mobile networks), they will all appear to have the same source IP. This would cause them all to be "stuck" to the same backend server, potentially overloading it while others sit idle. Cookie-based persistence is generally preferred because it’s tied to the individual browser, not the IP address.

The real power comes from understanding that the load balancer is essentially acting as a traffic cop with a very good memory, but that memory is stored in two places: the load balancer’s internal state and the user’s browser. If either of those memories gets corrupted or lost, your sticky session breaks.

The next thing people often struggle with is what happens when a backend server goes down. If app-01 fails, and a user was "stuck" to it, the load balancer needs to detect this failure. The user’s next request will hit the load balancer, which will try to send it to app-01, get an error back, and then realize app-01 is dead. At that point, it will assign the user to a different healthy server (say, app-02) and set a new sticky cookie for app-02. The user might experience a brief interruption or a lost session, but they will be redirected to a working server.

Want structured learning?

Take the full Load-balancing course →