Data
Redis
Sub-millisecond caching, queues and rate limiting, built by engineers who run what they ship.
Overview
Redis is an in-memory data-structure store. Because it keeps data in RAM rather than on disk, reads and writes return in well under a millisecond, and that single property is the reason it sits in front of so many systems. It is most often used as a cache, a session store, a rate limiter, a message broker and a job queue — the fast layer that absorbs load your primary database should never have to see. It is not, for most workloads, the place your data lives permanently, and treating it as one is the single most common way teams get Redis wrong.
What separates Redis from a plain key-value cache is that its values are real data structures, not just opaque blobs. Strings, hashes, lists, sets, sorted sets, streams, bitmaps and HyperLogLog each come with atomic operations tuned for them, so a great deal of application logic that would otherwise be a read-modify-write race against your database becomes a single atomic command. A leaderboard is a sorted set. A rate limiter is an atomic counter with an expiry. A work queue is a list or a stream. Modelling the problem to Redis’s data types, rather than bolting a cache onto an unchanged design, is where most of the value is won or lost.
Redis can persist to disk — through periodic RDB snapshots, an append-only file, or both — and it supports replication and Redis Cluster for high availability and horizontal scale. But persistence is always a trade-off against the speed that made you choose Redis in the first place, and durability guarantees are weaker than a database built for the job. We treat Redis as an accelerator and a coordination layer that complements a durable primary store such as PostgreSQL, never as a drop-in replacement for one. Used that way it is one of the highest-leverage pieces of infrastructure you can add; used as a system of record it becomes a liability the first time a node restarts.
Best for — Read-heavy and coordination-heavy workloads — caching, sessions, rate limiting, queues and leaderboards — where sub-millisecond latency and atomic data structures relieve a primary database that Redis complements rather than replaces.
Why teams choose Redis
Latency measured in microseconds
Because data lives in RAM and the protocol is lean, Redis answers in well under a millisecond even under heavy concurrency. Putting it in front of a slower primary store turns expensive, repeated queries into near-instant lookups, which shows up directly as faster pages and a database that is no longer the bottleneck.
Load taken off your primary database
A well-placed cache absorbs the reads your relational database was answering over and over, often removing the majority of its query load. That frequently means you can defer scaling the database, run fewer read replicas, and spend less — the cache pays for its own RAM many times over.
Atomic operations without race conditions
Counters, list pushes, set additions and sorted-set updates are atomic single commands, so rate limiting, queuing and ranking work correctly across many application instances without the locking gymnastics the same logic would need in a shared database. The correctness is built into the operation rather than bolted on afterwards.
Why businesses choose Redis
- You have measured that your primary database is straining under repeated reads or contention, and you want a fast layer in front of it rather than a bigger, more expensive database underneath.
- You need coordination that is correct across many application instances — rate limits, locks, counters, sessions — and want it atomic and central rather than approximate and per-instance.
- Your problem fits Redis’s data structures, and you want engineers who will model it to them properly instead of using Redis as a dumb byte cache and leaving most of its value on the table.
- You want honest advice on the boundary — what belongs in Redis, what belongs in PostgreSQL, and where a cache would add complexity without buying you anything — rather than a reflex to cache everything.
What we build with Redis
The capabilities this technology is genuinely strong at — and what we most often build with it.
Data structures, not just keys and values
Strings, hashes, lists, sets, sorted sets, streams, bitmaps and HyperLogLog each carry atomic operations suited to them. We model the problem onto the right structure — a sorted set for a ranked leaderboard, a hash for a session object, a set for deduplication — so logic that would be a race against your database becomes one atomic command.
Expiry and eviction as first-class tools
Every key can carry a time-to-live, and Redis can be configured to evict under memory pressure with policies such as least-recently-used. We use expiry deliberately — it is what makes a cache self-cleaning and a rate-limit window self-resetting — and we size memory and pick an eviction policy on purpose rather than discovering the default the hard way.
Atomic counters and rate limiting
INCR and its relatives increment atomically, so a rate limiter is a counter with an expiry and a sliding window is a sorted set of timestamps — correct across every application instance without a shared lock. This is one of the patterns Redis does better than almost anything else, and we lean on it rather than reinventing it in application code.
Pub/sub and Redis Streams
Redis can act as a lightweight message broker: pub/sub for fire-and-forget fan-out, and Streams for an append-only log with consumer groups, acknowledgements and replay. We reach for Streams when you need at-least-once delivery and backlog handling, and are candid about when a dedicated broker like Kafka is the better fit instead.
Persistence, replication and Redis Cluster
RDB snapshots and the append-only file give tunable durability; replication and Redis Cluster give high availability and horizontal sharding across nodes. We configure these to match how much you can afford to lose and how much load you need to spread, because the defaults rarely match a specific workload’s real requirements.
Lua scripting and atomic transactions
When a pattern needs several operations to happen as one indivisible unit, we use server-side Lua scripts or MULTI/EXEC transactions so the whole sequence runs atomically without a round-trip race. This is how distributed locks and multi-step updates stay correct under concurrency instead of merely looking correct in testing.
Use cases
Application and query caching
Sitting Redis in front of a relational database or an API to cache expensive query results, rendered fragments or computed values, with sensible time-to-live and invalidation — the classic use, and usually the one with the largest, fastest payoff.
Sessions, rate limiting and coordination
Central session storage shared across every application instance, plus atomic rate limiters, distributed locks and feature flags — the coordination layer that lets a horizontally scaled service behave as one system rather than many that disagree.
Leaderboards, counters and analytics
Sorted sets for real-time rankings and leaderboards, bitmaps and HyperLogLog for cheap approximate counting of unique visitors or events — problems that are awkward and slow in a database but a handful of commands in Redis.
Job queues and event streams
Lists as simple work queues and Redis Streams as an append-only event log with consumer groups and acknowledgements, moving slow work off the request path so users are not waiting on a task that could run in the background.
When Redis is the right choice
- You have a read-heavy workload where the same data is fetched far more often than it changes, and your primary database is spending real money answering questions it already answered a second ago. A Redis cache in front of it is one of the cheapest, highest-impact changes you can make.
- You need cheap atomic coordination across many application instances — rate limiting, distributed locks, session storage, feature flags, or counters — where doing it in your relational database means lock contention and doing it in application memory means every instance disagrees.
- The problem maps naturally onto Redis’s data structures: leaderboards and rankings onto sorted sets, queues and event streams onto lists or streams, presence and deduplication onto sets and HyperLogLog. When the data type fits, the code gets shorter and the operation gets atomic for free.
- Wrong for: your primary system of record. Redis is memory-first, persistence is a trade-off, and its durability and query model are not built to be the single source of truth for data you cannot afford to lose. Put that data in PostgreSQL and let Redis accelerate it.
- Wrong for: large datasets that must all live in RAM at once, or rich ad-hoc querying. If the working set does not fit in memory affordably, or you need joins, secondary indexes and complex filters, you are fighting the tool — that is a database’s job, not a cache’s.
Redis: pros and cons
Strengths
- Sub-millisecond reads and writes because everything is served from memory, which is a step-change in latency that no disk-backed database can match for hot data.
- Rich data types — hashes, lists, sets, sorted sets, streams, bitmaps and HyperLogLog — with atomic operations, so common patterns like leaderboards, queues and rate limits become a few commands rather than a subsystem.
- It is mature, ubiquitous and operationally well understood: excellent client libraries in every language, first-class managed offerings on every cloud, and a huge base of engineers who already know it.
- It does far more than caching — pub/sub, streams, distributed locks, session storage and vector search in newer versions — so one well-run piece of infrastructure can cover several needs instead of adding several tools.
Trade-offs
- Everything you keep in Redis must fit in RAM, and RAM is expensive. The working set is capped by memory and by budget, so Redis is unsuitable for large datasets you cannot afford to hold in memory all at once.
- It is memory-first, not durable-first. RDB snapshots and the append-only file give you persistence, but with weaker guarantees than a purpose-built database — a crash can lose the most recent writes — so Redis should not be the system of record for data you cannot lose.
- Persistence and replication cost performance and memory: snapshotting forks the process and the append-only file adds write overhead, so the more durability you demand, the more of Redis’s speed advantage you spend to get it.
- It is easy to misuse as a database rather than a cache or accelerator. Teams store canonical data in it, skip a primary store, and are surprised by data loss or the cost of memory — the failure is architectural, and it is common.
Architecture
The load-bearing decision with Redis is where its boundary sits: what is safe to lose and therefore fine to cache, versus what is canonical and must live in a durable store. We draw that line explicitly. Redis is the accelerator and the coordination layer; PostgreSQL or an equivalent primary database remains the source of truth. Getting this boundary wrong — canonical data with no home but Redis — is how teams end up losing records on a restart, so we settle it before writing cache code, not after an incident.
From there the work is modelling data to the right structures, choosing a caching strategy that fits the access pattern — cache-aside for most reads, write-through where staleness is unacceptable — and making invalidation deliberate rather than an afterthought, because a stale cache is a subtler bug than a slow query. We size memory for the real working set, pick an eviction policy on purpose, and decide up front how much durability the workload actually needs, since every guarantee added past caching costs some of the speed that justified Redis in the first place.
Performance
Redis is fast for a simple, structural reason: data is in RAM, the core is efficient, and the protocol is lean, so individual operations return in microseconds. The performance work is rarely about making a single command faster — it is about reducing round trips and keeping individual operations cheap. We batch with pipelining and MULTI, use server-side Lua to collapse multi-step logic into one call, and avoid the commands that scan large keyspaces or block the single-threaded core, because one slow O(n) command against a huge structure can stall everything behind it.
The honest performance caveats sit around durability and data shape. Turning on aggressive append-only persistence adds write overhead, and snapshotting forks the process and briefly doubles memory pressure, so more durability means less of the speed you came for — a trade we tune to the workload rather than maxing out by reflex. Large values, unbounded lists and hot keys are the usual culprits when Redis is slower than expected, and we design against them: bounded structures, sensible expiry, and keys spread so no single one becomes a bottleneck.
Security
Redis was originally built to run inside a trusted network, and that heritage shows: an unsecured, internet-exposed instance is a well-known way to get compromised. We treat network isolation as the first line of defence — Redis bound to a private network, never open to the public internet — with TLS in transit and authentication enabled through ACLs or a managed provider’s controls. On managed platforms we use their encryption, access controls and network rules rather than rolling our own.
Beyond the network, we scope access with Redis’s access-control lists so applications can run only the commands they need, disable or rename dangerous administrative commands in shared environments, and keep sensitive data out of Redis unless it genuinely belongs there — remembering that data in a cache is data in memory and, if persistence is on, on disk. Redis removes latency, not the need for the ordinary discipline of least privilege, encryption and treating every exposed port as attack surface.
Scalability
Redis scales vertically further than most people expect — a single node handles enormous request volume because each operation is so cheap — but it is bounded by one hard limit: the working set must fit in RAM, and RAM costs money. So the first scaling question is always what actually needs to be in Redis, and we are ruthless about keeping it to the hot, cache-worthy, coordination-critical data rather than letting it accrete everything.
When one node is not enough, replication spreads read load and provides failover, and Redis Cluster shards the keyspace across multiple nodes for horizontal capacity beyond a single machine’s memory. Both add operational complexity — cross-slot operations, failover behaviour, client support — so we adopt them when the workload demands it, not pre-emptively. On managed Redis we lean on the provider’s clustering and failover, and design keys and access patterns so that sharding, when it comes, does not require rewriting the application.
Redis integrations & ecosystem
The technologies we most often pair with it — each links to how we work with it.
How we work
We start by drawing the boundary: what is canonical and belongs in a durable store, and what is hot, derivable or coordination-related and belongs in Redis. That decision governs everything else, and getting it right up front is far cheaper than discovering a data-loss problem in production. We would rather tell you a cache will not help a particular workload than add one for the sake of it, because unnecessary caching is just complexity and a new class of staleness bugs.
When Redis fits, we model the problem to its data structures properly, make invalidation and expiry deliberate, and size memory and durability to the real requirement rather than the default. The engineers who design the caching and coordination layer are the ones who run it — that is what operating what we build means. It shows up as sensible eviction policies, monitored memory and hit rates, secured instances, and a design your own team can reason about, because a cache nobody understands is a cache that eventually surprises you.
The service behind it
Delivered throughData EngineeringWhat we build with Redis
The disciplines this technology most often shows up in — from a first build to taking over and stabilising an existing one.
How we deliver
- 01
Discover
We map the system, the constraints and the business it serves — including the parts nobody documented.
Architecture brief
- 02
Architect
Decisions get made, written down and defended before a line of production code exists.
Decision records
- 03
Build
Short cycles against working software. You see progress in the product, not in a status deck.
Shipping increments
- 04
Operate
Monitoring, incident response and iteration. The system is alive, so the engagement is too.
Runbooks & SLOs
Industries we use Redis in
Domain knowledge changes what gets built. A few of the sectors we know before the first meeting.
Also in Data
Why teams choose us for Redis
Senior engineers only
The value of Redis is almost entirely in judgement — where the boundary sits, which data structure fits, how to invalidate, how much durability to buy. That is earned on previous systems, not learned on yours. No juniors treating Redis as a magic speed-up on your project.
We operate what we build
We run the caching and coordination layers we ship, so we design for the day a node restarts and the week memory fills up, not just the demo. That means monitored hit rates, deliberate eviction, secured instances and a boundary that holds under failure.
Honest about the boundary
We will tell you plainly what should not go in Redis, when a cache would add staleness bugs without buying latency, and where PostgreSQL is the right home for data you cannot lose. We would rather leave a cache out than build you one that hides a data-loss risk.
We model the problem, not just cache bytes
Most teams use Redis as a dumb byte cache and leave most of its value unused. We map the actual problem onto sorted sets, streams, hashes and atomic counters, so the logic is shorter, correct under concurrency, and does more with the same infrastructure.
Typical timeline
- 01
Discovery and boundary design
One to two weeks measuring the workload, identifying where latency and load actually hurt, and settling what belongs in Redis versus the primary store before any cache code is written.
- 02
First integration
One to two weeks putting Redis in front of the highest-impact path — a hot query, a session store, a rate limiter — with real invalidation and expiry, and measuring the effect against a baseline.
- 03
Iterative rollout
Extending caching and coordination patterns across the system in short cycles, each measured, with memory sizing, eviction policy and monitoring handled as we go rather than deferred.
- 04
Hardening and handover
Tuning persistence and replication to the durability the workload needs, securing and isolating the instances, setting up alerting on memory and hit rate, and documenting so your team can own it.
How pricing works
- Fixed-scope engagements for a specific piece of work — introducing a caching layer, building a rate limiter or queue, or designing a session store — quoted once we understand the workload and its latency requirements.
- Monthly senior engagement for ongoing performance and infrastructure work where Redis is one part of a larger system and the scope evolves over time.
- Focused audits and rescues for existing Redis setups — runaway memory, a low cache hit rate, an instance being misused as a database, or an exposed and insecure deployment — priced by assessment.
Hire Redis engineers
Need Redis capacity on your own team? We embed named senior engineers into your existing team — reporting to your leads, working in your rituals — so you add capacity without a hiring cycle.
Hire Redis engineersCommon questions
Can Redis replace my database?
For almost every application, no — and treating it as a replacement is the most common way to get Redis wrong. Redis is memory-first: your data must fit in RAM, persistence is a trade-off against speed with weaker guarantees than a purpose-built database, and its query model is not designed to be a single source of truth. Use it as an accelerator and coordination layer in front of a durable store like PostgreSQL. There are narrow cases where Redis is the right primary store, but you should reach that conclusion deliberately, not by drifting into it because caching felt fast.
How does Redis handle persistence, and can it lose data?
It offers two mechanisms: RDB snapshots, which save a point-in-time copy periodically, and the append-only file, which logs every write for replay. You can run either or both. But both are trade-offs against performance — snapshotting forks the process and the append-only file adds write overhead — and neither matches the durability of a database built for the job. Depending on configuration, a crash can lose the most recent writes. So yes, Redis can lose data, which is exactly why we keep anything you cannot afford to lose in a durable primary store and let Redis accelerate it.
What actually belongs in Redis versus PostgreSQL?
PostgreSQL holds the canonical data — the records that must survive, that you query in rich ways, that you cannot afford to lose. Redis holds what is hot, derivable or coordination-related: cached query results, sessions, rate-limit counters, leaderboards, queues, locks. A useful test is whether losing it on a restart would be a catastrophe or a brief cache miss. If catastrophe, it belongs in the database; if a re-fetch, it is a fine candidate for Redis. Drawing that line clearly is the most important architectural decision, and we settle it before writing cache code.
Is Redis still open source after the licensing change?
The picture changed in 2024. Redis moved away from its permissive open-source licence to source-available terms (SSPL and the Redis Source Available Licence), which restrict how managed providers can offer it commercially. In response the community, backed by the Linux Foundation, forked the last open-source version as Valkey, which remains under the original permissive licence and is broadly compatible. For most teams this changes little day to day — both are excellent and drop-in compatible — but it does matter for licensing and vendor strategy, and we will walk you through which is the right choice for your situation rather than pretending the change did not happen.
Why is our Redis running out of memory or getting slow?
Almost always one of a few causes: no expiry or eviction policy set, so keys accumulate forever; large values or unbounded lists and sets growing without limit; a hot key that every request hammers; or Redis quietly being used to store canonical data it was never meant to hold. Slowness usually traces to O(n) commands scanning big structures on the single-threaded core, or aggressive persistence adding overhead. Each has a concrete fix — deliberate expiry, bounded structures, key sharding, moving canonical data out — and an audit finds which one you have rather than guessing. This is one of the most common rescues we do.
Building on Redis?
A technical conversation with the engineers who would do the work. If we are not the right fit, we will say so on the call.