All posts
5 min read

Redis: When a Small App Actually Needs It (and When Postgres Is Enough)

Redis shows up in every architecture diagram, and AI tools add it by reflex. It's excellent at a few specific jobs — caching, rate limiting, ephemeral state, pub/sub — and unnecessary for many small apps. What it's for, what it isn't, and how to use it without losing data you cared about.

databasesinfrastructurearchitectureintermediate

Ask an AI tool to make an app "production-ready" and there's a good chance Redis appears: a cache here, a session store there, a job queue. Redis is genuinely excellent software. It's also one more service to run, secure, pay for, and understand — and for many small apps, Postgres already does the job well enough.

Here's how to tell the difference.

What Redis is

Redis is an in-memory data store. It keeps data in RAM, which makes reads and writes extremely fast — typically well under a millisecond. It stores data under keys, with rich data types: strings, hashes, lists, sets, sorted sets, streams, and more. Keys can expire automatically after a set time.

(Redis changed its licence in 2024, and the Linux Foundation's Valkey fork emerged as an open-source, compatible alternative; Redis later added an open-source licence option again. Many managed providers offer one or both. For your application code, they're effectively interchangeable.)

What Redis is great at

1. Caching

Store the result of an expensive computation or slow query, with an expiry:

const key = `product:${id}`
let product = await redis.get(key)
if (!product) {
  product = JSON.stringify(await db.getProduct(id))
  await redis.set(key, product, { EX: 300 })   // cache for 5 minutes
}

Good when the same expensive result is requested often and slightly stale data is acceptable.

2. Rate limiting

Counting requests per user per minute, with counters that expire on their own, is a textbook Redis job — fast, atomic increments shared across all your app instances. (How to Stop Bots From Running Up Your AI App's Bill.)

3. Ephemeral, high-churn state

Presence ("who's online"), short-lived tokens, typing indicators, temporary locks. Data that changes constantly and doesn't need to survive forever.

4. Pub/sub and real-time fan-out

Broadcasting a message to every app instance — for example, so a websocket server on instance A can notify users connected to instance B.

5. Leaderboards and counters

Sorted sets make "top 100 scores" or "most viewed this hour" trivial and fast.

6. Job queues (sometimes)

Popular queue libraries — BullMQ (Node), Sidekiq (Ruby), Celery (Python) — use Redis. They're mature and fast.

When Postgres is enough

Here's the part AI tools skip. For a small or medium app, Postgres can often do these jobs well enough, with one less service:

  • Job queues — Postgres-backed libraries (pg-boss, Graphile Worker, Solid Queue, Oban, Procrastinate) are reliable and let you enqueue a job in the same transaction as the data it concerns. (Your App Needs Background Jobs.)
  • Sessions — a sessions table works fine at small scale; many auth libraries support it directly.
  • Caching — often the real fix for a slow query is an index, not a cache. (Database Indexes: Why Your App Got Slow.) And frameworks have their own caches.
  • Rate limiting — a simple counter table works at modest volume.
  • Pub/sub — Postgres has LISTEN/NOTIFY for lightweight notifications.

The honest rule of thumb: add Redis when you have a specific need that Postgres handles badly — not because a diagram had it. Signs you've reached that point: very high request rates on the same keys, rate limiting across many instances under load, real-time fan-out, or a queue library you specifically want that requires it.

The catch: it's memory, and it can forget

Redis's speed comes from keeping data in RAM. That has consequences:

  • Persistence is configurable, not guaranteed. Redis can write snapshots (RDB) and/or an append-only log (AOF) to disk, but depending on settings, a crash can lose recent writes. Many managed caches run with persistence off.
  • Memory is finite. When Redis fills up, it either rejects writes or evicts keys according to its maxmemory-policy. For a cache, evicting old keys is exactly right. For a job queue, silently evicting jobs is a disaster.

So: treat Redis as a cache unless you've deliberately configured it otherwise. Anything you can't afford to lose — orders, payments, user data — belongs in Postgres. If you use Redis for queues, use a noeviction policy and persistence, and monitor memory.

Caching without regret

Caches introduce a classic problem: stale data. A few habits:

  • Always set an expiry (EX). A cache without expiry is a slow memory leak.
  • Invalidate on write — when a product is updated, delete its cache key.
  • Namespace keys — product:42, user:7:settings — so you can reason about and clear them.
  • Never cache per-user data under a shared key. A cache key that doesn't include the user ID can serve one user's data to another.
  • Measure first. Cache what's actually slow and frequently requested, not everything.

Security basics

  • Never expose Redis to the internet. It should only be reachable from your app's network. Exposed Redis instances are routinely found and abused.
  • Require authentication (a password or ACL user) and use TLS where the provider supports it.
  • Keep the connection string in an environment variable (commonly REDIS_URL). (What Is an Environment Variable?)

A quick decision guide

Need Start with
Background jobs Postgres-backed queue
Sessions Postgres (or your auth provider)
Slow query An index, then a cache if still needed
Rate limiting across many instances Redis
Real-time fan-out / presence Redis
Leaderboards, high-rate counters Redis
Anything you can't lose Postgres

EasySpawn provisions Redis alongside Postgres on the Team plan, delivered to your app as REDIS_URL on a private network — so when you do need it, it's one setting rather than one more service to run. See pricing or join the waitlist.

Related: Postgres Connection Pooling Explained · Which Database Should an AI-Built App Use? · What Is Caching? · Preventing Cache Stampedes

Keep reading