When I started learning Redis, I had one big question: "If thousands of people are using the same app at the same time, how does the app know whose data belongs to whom?"
Turns out, the answer is simpler than I thought, but it took me a while to fully connect the dots. So I'm writing this post the way I wish someone had explained it to me: in plain English, no jargon left unexplained.
What is Redis, in one sentence?
Redis is a super-fast, temporary storage box that sits between your app's backend and your database. Instead of asking the (slower) database the same question over and over, your app can ask Redis first. If Redis already has the answer stored, it replies instantly.
Think of it like a librarian who keeps the 10 most-requested books on her desk instead of walking to the back shelf every single time someone asks for them.
The big question: how does Redis know which data belongs to which user?
Redis doesn't magically "know" anything. It's just a giant dictionary. You give it a key, it gives you back a value. That's it.
key → value
"hello" → "world"
So the real trick isn't in Redis itself. It's in how your backend code names the keys.
The pattern: build the key from the user's identity
Every time a user logs in, they get some kind of unique ID (a session ID, a token, whatever). Your backend uses that ID to build a unique key for each piece of data:
user:123:profile
user:123:cart
user:456:profile
user:456:cart
User 123 and user 456 never touch each other's data, because they're stored under completely different keys, even though it's the exact same Redis, being hit by both users at the exact same time.
Simple analogy: imagine a huge wall of PO boxes at a post office. Every box has a number. Redis is just the wall of boxes, it doesn't care who owns which box. Your app's job is to always use the right box number (key) for the right person.
What about the same question with different details?
Here's where it got interesting for me. Say a user asks for "my orders," but sometimes they want pending orders, sometimes delivered orders, sometimes page 1, sometimes page 2. It's the "same" request, just with different filters (called query parameters).
The solution: the filters become part of the key too.
user:123:orders:status=pending
user:123:orders:status=delivered
user:123:orders:page=1
user:123:orders:page=2
Same user, same "operation," but different filters means different Redis entries. Next time the exact same filters come in, the backend rebuilds the exact same key, finds the cached answer, and skips the slow database call entirely.
A neat trick: hashing long filters
If there are a lot of filters, keys can get messy. So a common trick is to squish all the filters into one short fingerprint using something called a hash function (like MD5 or a faster one like xxHash):
Input: {"status": "pending", "page": 1, "limit": 10}
Output: e4d7f1b4ed2e42d15898f4b27b019... (a fixed-length code)
Same input always produces the same fingerprint. So instead of matching keys, the backend just re-generates the fingerprint from the new request and checks if it already exists in Redis. No decoding needed, you never need to reverse a hash, you just recreate it.
Important: this fingerprint is purely an internal backend detail. The frontend never sees it, never sends it, and doesn't need to know it exists. The frontend just sends normal filters like ?status=pending, and gets back normal data like JSON. Nothing about hashing or Redis is visible to it.
"But doesn't the whole website get cached too?"
This was my next confusion, since the UI (the buttons, layout, colors) looks the same for every user, is that cached in Redis too?
Nope. That's a completely different system called a CDN (Content Delivery Network).
- CDN = caches the static stuff (HTML, CSS, JavaScript, images) that's identical for every visitor. It stores copies of these files on servers physically located all around the world, so you always download them from whichever copy is nearest to you, instead of from one single far-away server.
- Redis = caches the personal stuff (your cart, your profile, your orders) that's different for every user.
Simple analogy: a CDN is like a chain of local libraries, each holding a copy of a popular book so you don't have to travel across the country to the one original library. Redis is like your own personal mailbox, nobody else's mail goes into it, no matter how many mailboxes are on the same street.
Let's actually try it: Redis with Python
Reading about Redis is one thing, but running it yourself makes it click much faster. Here's the minimum you need to get hands on.
Step 1: Download and install Redis
You can get Redis (and see the official docs) from redis.io. On Mac, the easiest way is Homebrew:
brew install redis
brew services start redis
On Linux, you can install it through your package manager, and on Windows, the official docs point you toward using WSL or Docker. Once installed, you can test the server directly with the command line tool that ships with it:
redis-cli ping
If it replies PONG, Redis is running and ready.
Step 2: Try some basic Redis commands
You don't even need Python yet to get a feel for how Redis stores data. Open redis-cli and try:
SET user:123:name "Vignesh"
GET user:123:name
SET user:123:cart "2 items"
EXPIRE user:123:cart 60
TTL user:123:cart
DEL user:123:name
A quick rundown of what each command does:
-
SET key valuestores a value under a key. -
GET keyfetches the value back. -
EXPIRE key secondsmakes the key automatically disappear after a set number of seconds (useful for temporary cached data). -
TTL keytells you how many seconds are left before a key expires. -
DEL keydeletes a key immediately.
Step 3: Install Redis in Python
The official Python client is called redis. Install it with pip:
pip install redis
If you want faster response parsing, you can install it with an optional extra:
pip install "redis[hiredis]"
Step 4: Use Redis from Python
Here's a small working example, connecting to Redis, setting a value, and reading it back:
import redis
r = redis.Redis(
host="localhost",
port=6379,
db=0,
decode_responses=True # returns normal strings instead of bytes
)
# check the connection
print(r.ping()) # True
# store a value, matching the user:id:resource pattern from earlier
r.set("user:123:cart", "2 items")
# read it back
print(r.get("user:123:cart")) # "2 items"
# set a value that expires after 60 seconds
r.setex("user:123:session", 60, "active")
# store multiple fields under one key using a hash
r.hset("user:123:profile", mapping={"name": "Vignesh", "role": "student"})
print(r.hgetall("user:123:profile"))
This is the exact same pattern discussed earlier in this post, just written in real, runnable code. Once you connect this into a small Flask or FastAPI app, you have the full picture: a request comes in, the backend builds a key like user:123:orders, checks Redis first with r.get(), and only hits the database if it's a cache miss.
Putting it all together
Here's the full journey of a single click, from a fresh understanding:
- You open a website. Static UI files load from the nearest CDN location.
- You click something. The app calls the backend, sending your user ID.
- The backend builds a specific key using your user ID plus what you asked for.
- It checks Redis first. If the answer's already there, it replies instantly.
- If not, it asks the actual database, gets the answer, saves it in Redis for next time, and replies to you.
Two completely different caching systems, solving two completely different problems, but built on the exact same core idea: don't redo expensive work if you already have the answer stored somewhere fast.
If you're learning backend development or AWS, I'd love to hear what confused you the most when you first learned about caching. Drop a comment below!
Top comments (0)