Security

Storing and Handling Sessions in Backend - Interview Question

HTTP is stateless. Every request is independent. The server has no memory of who you are between requests. Sessions solve this. They give the server a way...

16 Apr 2024

Storing and Handling Sessions in Backend - Interview Question

HTTP is stateless. Every request is independent. The server has no memory of who you are between requests. Sessions solve this. They give the server a way to remember a user across multiple requests.

This is a common interview question, and the answer reveals how well someone understands backend architecture. The choice of session storage affects scalability, reliability, and security.

Option 1: In-memory storage

Store sessions in a JavaScript object or Map on the server.

Ts
import express, { Request, Response } from 'express';
import session from 'express-session';

const app = express();

app.use(session({
  secret: 'your-secret-key',
  resave: false,
  saveUninitialized: false,
}));

app.get('/login', (req: Request, res: Response) => {
  req.session.userId = '12345';
  res.send('Logged in');
});

app.get('/profile', (req: Request, res: Response) => {
  if (req.session.userId) {
    res.send(`User: ${req.session.userId}`);
  } else {
    res.status(401).send('Not authenticated');
  }
});

Benefit: Zero setup. Fast reads and writes. Good for prototyping and local development.

Cost: Sessions die when the server restarts. Cannot scale horizontally. If you run two server instances behind a load balancer, a user hitting instance A has no session on instance B. Not viable for production.

Option 2: Redis

Store sessions in Redis. It is an in-memory data store, but it runs as a separate service that all your server instances can connect to.

Ts
import RedisStore from 'connect-redis';
import { createClient } from 'redis';

const redisClient = createClient({ url: 'redis://localhost:6379' });
await redisClient.connect();

app.use(session({
  store: new RedisStore({ client: redisClient }),
  secret: 'your-secret-key',
  resave: false,
  saveUninitialized: false,
  cookie: { secure: true, httpOnly: true, maxAge: 3600000 },
}));

Benefit: Survives server restarts. Shared across instances. Built-in TTL for automatic expiration. Sub-millisecond reads. This is the standard choice for production session storage.

Cost: Another service to operate. Redis needs monitoring, memory management, and backup configuration. If Redis goes down, all sessions are lost unless you have persistence enabled (RDB or AOF).

Option 3: Database

Store sessions in your existing database (PostgreSQL, MongoDB, etc.).

Benefit: No additional infrastructure. Sessions persist through server and cache restarts. Easy to query and audit.

Cost: Slower than Redis. Every request that reads session data hits the database. Under high traffic, session reads can become a bottleneck. You also need to implement your own session cleanup for expired records.

Option 4: JWTs (stateless sessions)

Skip server-side storage entirely. Encode the session data into a signed JWT and send it as a cookie or header.

Benefit: No server-side storage at all. Every server instance can validate the token independently. Scales infinitely. No session lookup on every request.

Cost: You cannot revoke a JWT before it expires. If a user logs out, the token is still valid until its TTL runs out. Workarounds exist (token blacklists, short TTLs with refresh tokens), but they reintroduce server-side state. Also, JWTs grow in size as you add claims. Large tokens increase request overhead.

How I answer this in interviews

I start with the problem: HTTP is stateless. Then I walk through the options from simplest to most scalable. For each one, I state the benefit and the cost. I end with my recommendation: Redis for server-side sessions in most production scenarios, JWTs when you need stateless authentication across services.

The interviewer is not looking for the "right" answer. They want to see that you understand the trade-offs and can reason about them.