Redis

Redis Session Store for Fast Retrieval and Update of User Data

June 9, 2026
6 min read

Every authenticated request needs user data: who they are, their permissions, their preferences. Fetching this from a database on every request is slow and wasteful. Redis as a session store puts that data in memory — available in microseconds, shareable across every server in your fleet.

Why Redis Over Database Sessions

Traditional session storage in a database has two problems: latency (a SQL query for every request) and stickiness (users are tied to one server). Redis solves both:

  • Speed — in-memory reads are sub-millisecond vs. 5-50ms for a database query
  • Centralized — all app servers share the same Redis, so any server can serve any user
  • Automatic expiry — TTL handles session cleanup without batch jobs
  • Atomic updates — HSET updates individual session fields without overwriting the entire session

Storing Sessions as Hashes

Redis Hashes are perfect for sessions — they store multiple fields in one key, and you can read or update individual fields without fetching the whole object.

# Create a session
HSET session:abc123 user_id 42 username "alice" role "admin" last_seen "2026-06-09T12:00:00Z"

# Set expiry (30 minutes)
EXPIRE session:abc123 1800

# Read the full session
HGETALL session:abc123

# Read a single field
HGET session:abc123 user_id

# Update one field without touching others
HSET session:abc123 last_seen "2026-06-09T12:05:00Z"

# Extend session on activity
EXPIRE session:abc123 1800

Python Implementation

import redis
import uuid
import json
from datetime import datetime

r = redis.Redis(host='localhost', port=6379, decode_responses=True)
SESSION_TTL = 1800  # 30 minutes

def create_session(user_id, username, role):
    session_id = str(uuid.uuid4())
    session_key = f"session:{session_id}"

    r.hset(session_key, mapping={
        'user_id': user_id,
        'username': username,
        'role': role,
        'created_at': datetime.utcnow().isoformat()
    })
    r.expire(session_key, SESSION_TTL)

    return session_id

def get_session(session_id):
    session_key = f"session:{session_id}"
    session = r.hgetall(session_key)

    if not session:
        return None  # expired or invalid

    # Extend TTL on access (sliding expiration)
    r.expire(session_key, SESSION_TTL)
    return session

def destroy_session(session_id):
    r.delete(f"session:{session_id}")

Sliding vs Absolute Expiration

Two TTL strategies for sessions:

  • Absolute expiration — set TTL once at login; session expires N minutes after creation regardless of activity. Simple, prevents forgotten sessions from living forever.
  • Sliding expiration — refresh TTL with every request. Session stays alive as long as the user is active. The EXPIRE call on every read achieves this.

Scaling Across Multiple Servers

With Redis sessions, horizontal scaling becomes trivial. Add servers — they all connect to the same Redis. No sticky sessions needed, no session replication between servers.

# All servers share the same Redis connection
# Server 1: user logs in
session_id = create_session(user_id=42, username="alice", role="admin")

# Server 2: user makes a request (different server, same session)
session = get_session(session_id)  # works perfectly

Security Considerations

  • Use cryptographically random session IDs — UUID v4 is fine; avoid sequential IDs
  • Store session ID in an HttpOnly cookie — prevents JavaScript access
  • Regenerate session ID after login — prevents session fixation attacks
  • Don't store sensitive data in sessions — keep sessions lean; store passwords or payment data elsewhere
  • Enable Redis AUTH and TLS — protect session data in transit and at rest

Key Takeaways

  • Redis Hashes map naturally to session objects — store, update, and read individual fields atomically
  • EXPIRE on every read implements sliding expiration with zero extra infrastructure
  • Shared sessions across all app servers eliminate sticky sessions and simplify scaling
  • Keep sessions small — store IDs and roles, not entire user objects
  • Destroy sessions explicitly on logout, don't just wait for TTL