This is a genuinely good confusion, because two true statements look contradictory: “REST is stateless” and “there’s a session cookie.” Let me resolve it.

“Stateless” means: the server keeps no memory of you between requests. Each request must carry everything the server needs to handle it. The server doesn’t remember “oh, this is the guy from 3 requests ago” on its own.

So how does a session work then? The client carries the state’s key — the cookie holds a JSESSIONID, and sends it on every request. The server doesn’t remember you; you remind the server who you are, every single time. That’s actually still “stateless-ish” from the server’s view — it’s reacting to what the request carries, not to its own memory.

Now your three sub-questions:

  • What if there’s no cookie? Then there’s no session — the server treats you as brand new. First-ever request has no cookie; the server creates a session and sends Set-Cookie: JSESSIONID=... back; the browser stores it and sends it on subsequent requests. No cookie = no continuity = truly stateless. (Pure REST APIs often work exactly this way — no session at all; instead each request carries a token, like a JWT in the Authorization header, which is the “carry your identity every time” idea without a server-side session.)

  • “How is it stateless if there’s a cookie?” Because the cookie lives on the client, not the server. The server holding no memory = stateless. The client re-presenting a cookie each time doesn’t break that — the state’s home is the browser, and for the server each request is self-contained.

  • Sticky load balancer / Redis session store — you’ve already spotted the exact problem this creates. If the session object lives in one server’s memory (classic Tomcat), and you have 5 servers behind a load balancer, then request 2 might hit a different server that doesn’t have your session. Two fixes, both of which you named:

    • Sticky sessions — the load balancer pins you to the same server every time (by cookie/IP), so your in-memory session is always there. Simple, but fragile: that server dies, your session’s gone, and load balances unevenly.
    • External session store (Redis) — pull the session out of any single server’s memory into a shared Redis. Now all servers read the same session; any server can handle any request. This is the modern answer, and it makes your app horizontally scalable and restart-safe. Spring Session does exactly this.

    The senior framing: “In-memory sessions force sticky load balancing, which doesn’t scale or survive restarts. Externalizing to Redis makes the app truly stateless per-node, so any instance handles any request.” That’s a strong thing to say.

LB

C- Sticky load balancer / Redis session store — you’ve already spotted the exact problem this creates. If the session object lives in one server’s memory (classic Tomcat), and you have 5 servers behind a load balancer, then request 2 might hit a different server that doesn’t have your session. Two fixes, both of which you named:

- **Sticky sessions** — the load balancer pins you to the _same_ server every time (by cookie/IP), so your in-memory session is always there. Simple, but fragile: that server dies, your session's gone, and load balances unevenly.
- **External session store (Redis)** — pull the session _out_ of any single server's memory into a shared Redis. Now _all_ servers read the same session; any server can handle any request. This is the modern answer, and it makes your app **horizontally scalable** and restart-safe. Spring Session does exactly this.

The senior framing: _"In-memory sessions force sticky load balancing, which doesn't scale or survive restarts. Externalizing to Redis makes the app truly stateless per-node, so any instance handles any request."_ That's a strong thing to say.