Skip to content
Home › SQL Comparisons › Redis vs PostgreSQL
Comparison · Database Engines

Redis vs PostgreSQL

Redis is an in-memory data structure server usually placed next to a database for caching, sessions, rate limits and queues; PostgreSQL is a durable relational database. The real decision is rarely one or the other: it is whether your workload needs Redis at all, or whether PostgreSQL features such as UNLOGGED tables, SKIP LOCKED queues and LISTEN/NOTIFY cover it.

Last verified October 2026. Versions checked: Redis 8.10, PostgreSQL 18.6. Licensing and features change; check the official sources for the latest details.

Quick verdict

Short answer

Use PostgreSQL as the system of record in either case. Add Redis (or its BSD-licensed fork Valkey) when you need sub-request-time data structures at high request rates: a shared cache in front of PostgreSQL, sessions with expiry, counters, rate limiters, leaderboards or stream-based queues with consumer groups. If your volumes are modest and you would rather run one system, PostgreSQL can act as a job queue with FOR UPDATE SKIP LOCKED, a scratch cache with UNLOGGED tables and a wake-up channel with LISTEN/NOTIFY, each with documented limits explained below.

How we know: This comparison is research-based: PostgreSQL behaviour (UNLOGGED tables, LISTEN/NOTIFY, SKIP LOCKED, asynchronous commit) was checked against the PostgreSQL 18 documentation, and Redis versions, streams, licences and prices against redis.io, valkey.io and the Amazon ElastiCache pricing page, in October 2026. We have not run performance tests, so no throughput or latency figures are given.

Redis keeps its dataset in memory and serves it through commands on data structures (strings, hashes, lists, sets, sorted sets, streams, JSON and more). The current release listed in the Redis documentation is 8.10. Redis 8 and later are offered under a choice of RSALv2, SSPLv1 or AGPLv3; Valkey, the Linux Foundation fork of Redis 7.2.4, is BSD licensed and at 9.1.2 (1 September 2026). How Redis compares with a document database, including its persistence options and licence history in detail, is covered in Redis vs MongoDB.

PostgreSQL is an open source relational database under the PostgreSQL Licence, at 18.6. Every committed change is written to the write-ahead log (WAL) before it is acknowledged, unless you choose otherwise, and it offers SQL, constraints, MVCC transactions and jsonb. It is not an in-memory store, but it has several features that overlap with jobs teams often give to Redis.

This page is about that overlap: when Redis earns its place next to PostgreSQL, and when PostgreSQL alone is enough.

Side by side

AspectRedisPostgreSQL
Typical role Cache, session store, rate limiter, counters, leaderboards, queues, pub/sub Durable system of record with SQL, constraints and transactions
Where data lives In memory; optional RDB snapshots and AOF on disk On disk, protected by the WAL; shared buffers cache hot pages
Expiry Per-key TTL (EX, EXPIRE) and eviction policies No per-row TTL; delete expired rows yourself, for example on a schedule
Queues Lists, and streams with consumer groups (XREADGROUP, XACK, pending entries list) A table plus SELECT ... FOR UPDATE SKIP LOCKED; jobs commit with the business data
Notifications Pub/sub channels; streams for durable fan-out LISTEN/NOTIFY, delivered at commit to sessions currently listening, payload under 8000 bytes by default
Trading durability for speed Choose RDB, AOF (appendfsync policy), both or none UNLOGGED tables (truncated after a crash) or synchronous_commit = off per transaction
Licence Redis 8+: RSALv2, SSPLv1 or AGPLv3; Valkey: BSD PostgreSQL Licence (permissive)
Main trade-off A second system to run, secure and keep consistent with the database Fewer moving parts, but cache and queue load competes with transactional work on the same server

Key differences

Complements first: Redis in front of PostgreSQL

The common architecture keeps PostgreSQL as the source of truth and puts Redis beside it for data that is read very often, changes quickly, or can be rebuilt: rendered pages or query results, session tokens, per-user rate-limit counters, feature flags, leaderboards in sorted sets, and background jobs in lists or streams. Redis gives each of these a purpose-built structure and per-key expiry, and it takes that traffic off the database's connections and buffer cache.

The cost is a second system: memory sizing, high availability, security, client libraries, and above all keeping the cache consistent with PostgreSQL. Every write path that changes cached data has to invalidate or update the cache, and the application has to tolerate a stale or missing entry. In our view that cost is worth paying when request rates are high or response times are tight, and often not worth it for a small internal application.

Queues: Redis streams versus SKIP LOCKED

Redis streams are documented as an append-only log with consumer groups: each message is delivered to one consumer in a group, tracked in a pending entries list until it is acknowledged, and can be claimed by another consumer if a worker dies.

// Redis (redis-cli): a job queue on a stream with a consumer group
XGROUP CREATE jobs workers $ MKSTREAM
XADD jobs * job_id 42 type send_email
XREADGROUP GROUP workers worker-1 COUNT 1 STREAMS jobs >
XACK jobs workers <id returned by XREADGROUP>

PostgreSQL can run the same pattern on an ordinary table. The PostgreSQL documentation says that SKIP LOCKED "provides an inconsistent view of the data, so this is not suitable for general purpose work, but can be used to avoid lock contention with multiple consumers accessing a queue-like table". Each worker claims a row that no other worker holds:

-- PostgreSQL 18: jobs table and a worker claiming one job
CREATE TABLE jobs (
  job_id     bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  payload    jsonb NOT NULL,
  status     text NOT NULL DEFAULT 'queued',
  created_at timestamptz NOT NULL DEFAULT now()
);

UPDATE jobs
SET status = 'running'
WHERE job_id = (
  SELECT job_id FROM jobs
  WHERE status = 'queued'
  ORDER BY job_id
  LIMIT 1
  FOR UPDATE SKIP LOCKED
)
RETURNING job_id, payload;

The PostgreSQL version has one property Redis cannot offer: the job can be inserted in the same transaction as the business change that caused it, so an order and its "send confirmation" job commit or roll back together. The trade-offs are that every claim is a write with WAL and vacuum cost on the same server as your application data, and that very high job rates are where, in our view, a dedicated broker or Redis is the better fit.

Caching and durability: UNLOGGED tables and asynchronous commit

PostgreSQL lets you give up durability selectively. The CREATE TABLE documentation says data in an UNLOGGED table is not written to the WAL, "which makes them considerably faster than ordinary tables. However, they are not crash-safe: an unlogged table is automatically truncated after a crash or unclean shutdown." Their contents are not replicated to standby servers, their indexes are unlogged too, and partitioned tables cannot be unlogged. That profile matches a cache: losing it after a crash is acceptable.

-- PostgreSQL 18: a cache table with expiry handled in SQL
CREATE UNLOGGED TABLE cache_entries (
  cache_key  text PRIMARY KEY,
  value      jsonb NOT NULL,
  expires_at timestamptz NOT NULL
);

INSERT INTO cache_entries (cache_key, value, expires_at)
VALUES ('product:1001', '{"name": "Desk", "price": 120}', now() + interval '10 minutes')
ON CONFLICT (cache_key) DO UPDATE
  SET value = EXCLUDED.value, expires_at = EXCLUDED.expires_at;

SELECT value FROM cache_entries
WHERE cache_key = 'product:1001' AND expires_at > now();

-- run periodically: PostgreSQL has no per-row TTL
DELETE FROM cache_entries WHERE expires_at <= now();

Two limits matter. An unlogged cache lives on the primary only, so reads from replicas do not see it; and it still uses the same memory, connections and vacuum as the rest of the database. Redis, by contrast, expires keys itself and can evict under memory pressure with policies such as allkeys-lru.

For durable tables, PostgreSQL also offers asynchronous commit. The documentation explains that with synchronous_commit off, the risk is "data loss, not data corruption": the window is at most three times wal_writer_delay, and because transactions are replayed in commit order no inconsistency is introduced. It can be set per transaction. Redis offers a similar dial through its persistence settings (RDB snapshots, AOF with appendfsync everysec or always), but its defaults and its data model start from memory, while PostgreSQL's start from full durability.

Notifications: LISTEN/NOTIFY versus pub/sub

PostgreSQL's NOTIFY sends a message on a named channel to every session that has run LISTEN on it. The documentation states that notifications sent inside a transaction are not delivered "until and unless the transaction is committed", that the payload must be shorter than 8000 bytes in the default configuration, that identical notifications in one transaction are folded into one, and that if the notification queue (8 GB in a standard installation) fills up, transactions calling NOTIFY fail at commit. Sessions that are not listening at the time do not receive the message later.

-- PostgreSQL 18: wake workers when a job is queued
LISTEN jobs_ready;                       -- in each worker session
SELECT pg_notify('jobs_ready', '42');   -- in the producer, inside its transaction

That makes LISTEN/NOTIFY a good wake-up signal paired with a jobs table (workers still claim rows with SKIP LOCKED, so nothing is lost if a worker was offline), and a poor message bus on its own. Each listener also needs a dedicated session, which needs care behind connection poolers that reuse sessions per transaction. Redis pub/sub is likewise fire-and-forget; when messages must survive a disconnected consumer, Redis streams are the Redis answer.

Licences, Valkey and managed services

PostgreSQL's licence is permissive and has not changed. Redis moved from BSD to RSALv2/SSPLv1 with 7.4 and added AGPLv3 as an option from 8.0 (details in Redis vs MongoDB). Valkey continues the BSD-licensed line from Redis 7.2.4, and Amazon ElastiCache now offers Valkey, Redis OSS and Memcached, pricing Valkey lower than the other engines. Valkey is a separate code base, so features added to Redis after the fork, such as the Redis 8 JSON and search integration, should not be assumed to exist in Valkey; check its own documentation.

In our view, for a cache or queue next to PostgreSQL the client protocol and core commands are what most applications use, and both Redis and Valkey provide them. If licence terms are a concern for a self-hosted or redistributed deployment, read the licence texts; we describe them but do not give legal advice.

Pricing and licensing

Self-managed. PostgreSQL, Redis Open Source and Valkey are free to run under their licences. Using PostgreSQL alone for queues and caching avoids a second server; adding Redis means paying for memory sized to the working set.

Redis Cloud. Listed on the Redis pricing page in October 2026, in USD: Free (up to 30 MB), Essentials from 0.007 per hour (5 per month), and Pro from 0.014 per hour with a 200 per month minimum, on AWS, Google Cloud and Azure.

Amazon ElastiCache. Serverless (billed per GB-hour of data stored and per million ElastiCache Processing Units) or node-based (per node-hour). Listed on the ElastiCache pricing page in October 2026 for ElastiCache Serverless for Valkey in US East (N. Virginia): 0.084 USD per GB-hour and 0.0023 USD per million ECPUs. AWS states that Valkey is 33% lower than the other engines on Serverless and 20% lower on node-based clusters.

Managed PostgreSQL (Amazon RDS and Aurora, Azure Database for PostgreSQL, Google Cloud SQL, and others) is billed by each provider for instances or capacity units, storage and I/O; use the provider's calculator.

Pricing checked on the vendors' official pages on 7 October 2026. Prices change; confirm before buying.

Where each one leads

Redis strengths

  • Purpose-built in-memory structures: sorted sets, streams with consumer groups, hashes, counters and more
  • Per-key expiry and eviction policies make caching and sessions simple
  • Takes high-rate, short-lived traffic off the primary database
  • Available as Redis Cloud, as Valkey or Redis OSS on ElastiCache, and self-hosted
  • Valkey offers a BSD-licensed option with the familiar protocol

PostgreSQL strengths

  • Jobs and business data can commit in the same transaction
  • SKIP LOCKED queues, UNLOGGED tables and LISTEN/NOTIFY cover modest queue, cache and signalling needs without a second system
  • Per-transaction durability control with synchronous_commit, without risking corruption
  • Full SQL, constraints and a permissive licence that has not changed

Limitations

Redis limitations

  • A second system to size, secure, monitor and keep consistent with the database
  • Dataset bounded by memory, and persistence settings trade safety against speed
  • Pub/sub messages are lost if no subscriber is connected; streams are needed for durable delivery
  • Licence changes since 2024 mean organisations may need to choose between Redis and Valkey

PostgreSQL limitations

  • No per-row TTL; expired rows must be deleted by your own job
  • UNLOGGED tables are truncated after a crash and not replicated to standbys
  • Queue and cache traffic adds WAL, vacuum and connection load to the same server
  • NOTIFY payloads are limited to under 8000 bytes by default and are not stored for absent listeners

When to choose each

Choose Redis if

  • Request rates are high enough that cache hits must not touch the database
  • You need sessions, tokens or rate-limit counters with automatic expiry
  • You need leaderboards, counters or real-time features built on sorted sets and atomic increments
  • You run a high-volume job or event pipeline and want streams with consumer groups

Choose PostgreSQL if

  • You want one system and your queue and cache volumes are modest
  • Jobs must commit or roll back together with the data that created them
  • A cache that can be lost on crash is acceptable and replicas do not need to read it
  • You want to avoid running and licensing a separate in-memory server

When neither is right

  • You need a durable event log with long retention and replay across many consumers: a dedicated streaming platform or message broker fits better than either.
  • You are choosing a document database rather than a cache: see MongoDB vs PostgreSQL and Redis vs MongoDB.
  • You want a serverless key-value store on AWS with per-request billing: see DynamoDB vs PostgreSQL.
  • Your load is analytical rather than transactional: see ClickHouse vs PostgreSQL.

Final recommendation

Bottom line

Start with PostgreSQL as the system of record, and in our view start without Redis unless you already know you need it: SKIP LOCKED job tables, UNLOGGED cache tables and LISTEN/NOTIFY cover many small and medium applications, with the bonus that jobs commit with your data. Add Redis or Valkey when request rates, expiry-heavy data such as sessions and rate limits, or real-time structures such as leaderboards and high-volume streams would otherwise load the database. Choose between Redis and Valkey on features you need and licence terms you can accept.

Frequently asked questions

Can PostgreSQL replace Redis?

For modest workloads, often yes: a table with FOR UPDATE SKIP LOCKED works as a job queue, UNLOGGED tables work as a crash-tolerant cache, and LISTEN/NOTIFY wakes workers. It has no per-key expiry or in-memory data structures, and cache and queue traffic shares the server with your transactional work, so at high request rates Redis is usually the better tool.

Is SKIP LOCKED a good way to build a queue in PostgreSQL?

The PostgreSQL documentation names it as the way to avoid lock contention with multiple consumers on a queue-like table, while warning that it gives an inconsistent view and is not for general queries. It suits background jobs that should commit with your business data. Each claim is a write, so very high job rates are better served by a dedicated broker or Redis streams.

What happens to an UNLOGGED table after a crash?

PostgreSQL truncates it automatically after a crash or unclean shutdown. Its contents are also not replicated to standby servers. After a clean shutdown and restart, the data is kept.

Is LISTEN/NOTIFY a message queue?

No. Notifications are delivered at commit only to sessions listening at that moment, payloads are limited to under 8000 bytes by default, and nothing is stored for absent listeners. Use it as a wake-up signal next to a jobs table, not as the only record of work.

Should I use Redis or Valkey?

Both speak the same core protocol for caching and queues. Redis 8 adds features after the fork, such as integrated JSON and search, under RSALv2, SSPLv1 or AGPLv3; Valkey is BSD licensed and offered on Amazon ElastiCache at a lower price than the other engines, according to AWS. Check each project's documentation for the features you rely on.

Sources

Checked October 2026.

How we research comparisons: our editorial method.

More comparisons

Browse all SQL comparisons or the tools directory.