Redis vs. Couchbase for Java Caching: Where the Built-In Cache Stops

Published on
September 2, 2026

Couchbase sells a specific idea to Java teams: you do not need a cache in front of your database, because the cache is already inside it. Its own blog puts the argument in cost terms — with Redis "you will get good cache performance, but at the price of running two (or more) separate databases," while with Couchbase "all of this functionality is built in: no separate modules to install, no additional database technology needed."

That is a real argument, and for some workloads it is the right one. But the same post concedes, in its own words, that "Redis performs very well in the case of a pure cache" — and a pure cache is exactly what most Java teams comparing these two are shopping for. So the useful question in a Couchbase vs Redis decision is not which is faster. It is: when your cache is a bucket inside a database, what do you inherit along with it?

What you inherit changed in October 2025, when Couchbase Server 8.0 removed the bucket type that most caching deployments were built on. This article works through what replaced it, how expiry, eviction, locking and the Java API surface differ, and where each choice actually stops.

Couchbase vs. Redis: Two Different Shapes of Product

Couchbase Server is a distributed document database with a memory-first data path. Its documentation calls the RAM tier a Managed Cache: writes "enter the cache, and subsequently are placed onto a replication queue… and (in the case of items for Couchbase buckets) onto a disk queue, so as to be written to disk." Reads are served from RAM when the item is resident and fetched from disk when it is not. On top of that sit a Query Service with SQL++, indexing, full-text and vector search, and Eventing.

Redis is an in-memory data store whose values are data structures: strings, hashes, lists, sets, sorted sets, streams, JSON documents, bitmaps, HyperLogLogs. It persists asynchronously, but it does not pretend the disk is part of the read path. Valkey, the BSD-licensed fork, has identical data-structure and expiry semantics; the query-engine capability discussed below ships on Valkey as a separate module rather than in core, as does JSON. Our Valkey vs. Redis comparison covers the licensing split between the two.

Couchbase Server 8.0 Redis / Valkey

Working set larger than RAM

Supported — items eject to disk and are fetched back on read

Not in Redis Open Source or Valkey; Redis Software offers it via Flex

Durability of an acknowledged write

Per-operation durability levels — majority, majorityAndPersistActive, persistToMajority

Asynchronous by default; WAIT counts replica acknowledgements, WAITAOF confirms an fsync

Cache unit

Bucket (max 30 per cluster), configured as a whole

Key, with per-key TTL and per-instance policy

Value size ceiling

20 MB per item

512 MB per string; collections bounded by memory

Querying cached data

SQL++, secondary indexes, FTS, vector search

Key lookup, plus a query engine over defined indexes

Coordination primitives

CAS on every operation at no extra cost, plus a 30-second document lock

Atomic commands and Lua; locks, semaphores and rate limiters built on them

Production floor

Three nodes recommended; 4 GiB RAM minimum, 16 GiB recommended per node

One process to start; three primaries and three replicas for Redis Cluster, or a primary, a replica and three Sentinels for automatic failover

The first row is worth keeping in mind for the rest of this article. A working set larger than RAM is the advantage Redis Open Source and Valkey cannot match at any price, and it is easy to lose sight of once the smaller differences start piling up.

Couchbase's Case Against Redis, and Where It's Right

The honest version of Couchbase's argument deserves stating before any criticism of it. If Couchbase is already your primary database, your working set fits comfortably in the Data Service quota, and your access pattern is key lookups and SQL++ queries, then adding Redis buys you very little and costs you an extra system to size, patch, monitor, fail over and page someone about. Couchbase's blog is right that this is a real cost rather than a rhetorical one. Take the win and move on.

Two more things belong in Couchbase's column before the rest of this article starts subtracting from it. Its compare-and-swap is genuinely better than Redis's: a CAS value comes back on every operation at no extra cost, where the Redis equivalent is a WATCH/MULTI transaction you have to construct and retry yourself. And an acknowledged Couchbase write can be made durable per operation — majority, majorityAndPersistActive, persistToMajority — which is a stronger guarantee than a cache is normally asked for and stronger than Redis gives you by default.

What follows is about the second tier of work that accumulates around a cache, and about the specific defaults you inherit when the cache is a bucket. If none of it applies to you, the honest version above — take the win and move on — is the answer.

Couchbase 8.0 Removed the Bucket Type Cache Deployments Used

Couchbase inherited its caching story from Membase, and for most of its life it offered a Memcached bucket type: RAM-only, no replication, no persistence, speaking the memcached protocol. That is what a large share of "we use Couchbase as a cache" deployments were built on.

Couchbase Server 8.0, released in October 2025, removed it. From the release notes: "Memcached buckets, deprecated in 6.5.1, have been fully removed in 8.0.0. Cluster upgrades from earlier versions will fail if Memcached buckets are present. Remove all Memcached buckets before upgrading." The upgrade documentation repeats it: "The upgrade process exits with an error if you attempt to upgrade a cluster with Memcached buckets."

The prescribed replacement is the Ephemeral bucket — "an alternative to Couchbase buckets when you do not need data persistence," which Couchbase describes as "similar to Memcached buckets but support features such as rebalance, backup, query, and eventing." That is a genuine upgrade in capability. It also carries a default that anyone building a cache needs to look at before shipping.

A Cache That Refuses Writes When Full — By Default

Two naming points first, because both trip people up. Couchbase calls its persistent bucket type a "Couchbase bucket," so the type name collides with the product name — a Couchbase bucket persists to disk, an Ephemeral bucket does not. And Couchbase says ejection in its prose where its API says evictionPolicy and Redis says eviction; this article uses whichever word its source does.

Ephemeral buckets take one of two ejection policies, and Couchbase's REST documentation is explicit about which one you get if you do not choose: "Ephemeral bucket: noEviction (which is the default) or nruEviction."

Here is what noEviction means, in Couchbase's own words: "Couchbase Server does not remove data from the bucket when it fills. Instead, it returns an error when you try to load additional data into the bucket. To be able to load more data into the bucket, you must either increase the bucket's RAM quota or remove some data from the bucket."

For a session store or a queue you never want to silently lose, that is the correct and careful default. For a distributed cache, it inverts the contract. A cache is supposed to absorb an oversized working set by discarding the coldest entries; this one absorbs it by failing your writes. If you are moving a Memcached bucket to an Ephemeral bucket as part of an 8.0 upgrade, the behaviour on a full bucket flips from "evict" to "reject" unless you explicitly set nruEviction.

Redis's equivalent knob is maxmemory-policy, whose default is also noeviction — so the trap is not unique to Couchbase, and a Redis instance deployed without setting it has the same failure mode. The differences are in the escape hatch. Redis exposes ten policies rather than two, they apply per instance, and they can be changed at runtime with a single CONFIG SET maxmemory-policy allkeys-lru. Couchbase's equivalent is bucket configuration rather than server configuration, and changing it on a persistent bucket has historically required a bucket restart, a swap rebalance, or a graceful failover and recovery. A Couchbase bucket can be edited with noRestart=true to "prevent Couchbase Server from automatically restarting the bucket," but then "the new ejection policy does not take effect until you perform further steps" — a swap rebalance, or a graceful failover followed by delta recovery. Ephemeral buckets take the change with no further steps.

Eviction Granularity

The deeper difference is what each system lets you say about which entries go first.

Couchbase Redis / Valkey

Policy scope

Per bucket

Per instance

Recency-based

nruEviction — not-recently-used metadata

allkeys-lru, volatile-lru

Frequency-based

None

allkeys-lfu, volatile-lfu

Evict only entries that have a TTL

None

The volatile-* family

Evict shortest-lived first

None

volatile-ttl

Keep keys resident, spill values to disk

valueOnly ejection — Couchbase buckets only

Not in Open Source or Valkey; Redis Software Flex

Changed at runtime

Via REST, but a persistent bucket needs a restart, swap rebalance or failover; immediate on Ephemeral buckets

CONFIG SET

The volatile-* family has no Couchbase analogue, and it is the row that matters most for a mixed bucket. If you keep cache entries and durable state in one place — the thing Couchbase's pitch encourages — Redis lets you mark the cache entries with a TTL and instruct eviction to touch only those. Couchbase's NRU eviction sees one undifferentiated population and will eject whatever looks cold, which on a mixed bucket means your durable state is eligible.

The last-but-one row runs the other way, and it is the strongest thing in Couchbase's column. On a persistent Couchbase bucket, valueOnly ejection keeps keys and metadata in RAM while the values live on disk, and fullEviction drops the keys and metadata too. Couchbase's sizing guidance is that a Couchstore bucket — value-only by default — needs a memory quota of "at least 10% of your expected dataset size," while a Magma bucket can go down to "at least 1%." Magma defaults to full ejection precisely because it has to: as the docs put it, at a low memory-to-data ratio "retaining just the keys and metadata of documents can still consume significant portions of the allocated memory." Neither Redis Open Source nor Valkey has a disk-backed read path, so neither has an answer; Flex, in the commercial Redis Software and Redis Cloud tiers, spills warm keys and values to SSD while the working set and key indexes stay in RAM. If your cache is a terabyte and your budget is not, that is a real reason to look at Couchbase.

There is a catch worth naming, because it cuts against the upgrade path described above. Ejection to disk is a property of persistent Couchbase buckets. Ephemeral buckets — the prescribed replacement for the Memcached buckets that 8.0 removed, and the natural home for a pure cache — take only noEviction or nruEviction, and by definition have no disk to eject to. Couchbase's best answer to a working set larger than RAM is therefore reachable only by running your cache as a persistent database bucket, with the write amplification and disk queue that implies. Redisson has no answer to that particular pressure either — a near cache holds less data locally, not more. If the working set genuinely does not fit in affordable RAM, that is Couchbase's row.

Expiry: Two Traps, One Shared, One Not

Time-to-live is the load-bearing feature of any cache, and Couchbase's differs from Redis's in ways that reach Java code directly.

Mutations Wipe the TTL

Couchbase's Java SDK documentation states it plainly: "most operations will implicitly remove any existing expiration. Thus, when modifying a document with expiration, it is important to pass the desired expiration time." Its advice is blunt — "If you wish to use the expiration feature, then you should supply the expiry value for every mutation operation."

Since Couchbase Server 7.0 there is an opt-out:

collection.replace("session:42", updated,
        replaceOptions().preserveExpiry(true));

Reading the expiry back is also opt-in — getOptions().withExpiry(true) — so a naive read-modify-write cycle cannot even see the TTL it is about to clear, and the entry becomes immortal in a bucket you sized in RAM.

To be fair, Redis has a version of this. SET, GETSET, DEL and the *STORE commands clear the timeout, and SET … KEEPTTL is the equivalent opt-out. But the exposure is narrower: Redis documents that operations which "conceptually alter the value stored at the key without replacing it" — INCR, LPUSH, HSET — leave the timeout untouched. Updating one field of a cached hash does not disturb the key's expiry. In Couchbase, the unit of mutation is the document, so any replace resets the clock to zero unless you say otherwise.

In practice the trap mostly disappears behind a cache abstraction, because the abstraction owns the TTL. Redisson's RMapCacheNative takes it as an argument to the write:

// java.time.Duration — RMapCacheNative takes a Duration or an Instant,
// not the (long, TimeUnit) pair that RMapCache uses.
RMapCacheNative<String, Session> sessions = redisson.getMapCacheNative("sessions");

// per-entry TTL, expired server-side by Valkey/Redis — no client-side eviction task
sessions.put("session:42", new Session(userId), Duration.ofMinutes(30));

Session s = sessions.get("session:42");

RMapCacheNative delegates expiry to native hash-field TTL, which needs Redis 7.4+ or Valkey 9.0+. Where you need max-idle eviction as well as TTL, or have to support older servers, RMapCache gives you both at the cost of a client-side eviction task. Both are in the open-source edition, and both are covered in distributed caching in Java.

Expired Is Not the Same as Reclaimed

This one has no Redis equivalent, and it matters specifically because a Couchbase cache is sized by a RAM quota.

Couchbase separates logical expiry from physical deletion. Logically, an expired document is gone immediately: "a request to the server for an expired document will receive a response indicating the document does not exist." Correctness is safe. Physically, it is still there. Couchbase's documentation continues: "expired documents are actually deleted (i.e. cease to occupy storage and RAM) when an expiry pager is run," and "expired-but-not-purged items… will still be considered with respect to the overall storage size and item count."

The expiry pager "runs every 10 minutes by default." A tombstone then remains "for a default period of 3 days." Deletion is also triggered by an access to the document or by auto-compaction, so hot keys clean themselves up; the ten-minute window applies to the cold ones, which in a cache are most of them.

Redis's active expiry cycle is far more aggressive — it "tests a few keys at random amongst the set of keys with an expiration" on every pass of its background cycle, on top of passive expiry on access — so expired memory comes back in seconds rather than minutes. Against Couchbase's default 85% high water mark, ten minutes of expired-but-resident entries can be the difference between ejection starting and not starting. On a Couchbase bucket, the memory resident ratio and kv_ep_bg_fetched — "number of items fetched from disk" — show it happening; on an Ephemeral bucket there is no disk to fetch from, so watch the bucket's memory usage against its quota instead of its item count.

One classic Couchbase footgun does not reach Java. The wire protocol reads an expiry below 30 days as a relative offset and anything above it as an absolute Unix timestamp, so a raw 45-day integer expires the document instantly, having been read as a moment in 1970. SDK 3.x takes a Duration or an Instant and throws InvalidArgumentException rather than misreading it — worth knowing only if a Go or Python service shares your bucket.

Locking and Coordination: Where Couchbase and Redis Diverge Most

Caches attract coordination work. You end up needing to stop two instances rebuilding the same expensive entry, to serialize an update, to rate-limit a downstream, to run a job on exactly one node. This is where the two products diverge most sharply, and it is worth being precise about what Couchbase does and does not offer.

Couchbase's primary mechanism is optimistic locking through CAS, and it is good: "CAS operations incur no additional overhead. CAS values are always returned from the server for each operation." For a compare-and-swap on a single document, that is exactly right, and Redis's own WATCH/MULTI is clumsier by comparison.

Pessimistic locking is where it stops. Couchbase offers getAndLock, and the documentation states the ceiling: "A document can be locked for a maximum of 30 seconds, after which the server will unlock it." The behaviour when you ask for longer is the part that surprises people — it does not clamp to the maximum. From the same page: "Setting a lock greater than 30 seconds will cause Couchbase Server to set the lock duration at the Server's default value, which is 15 seconds." Ask for a minute, get fifteen seconds.

Three things follow from that, and all three are structural rather than tuning problems.

  • There is no renewal. The Java SDK's Collection exposes getAndLock and unlock and nothing else lock-related. touch and getAndTouch modify expiry, not lock duration. If your critical section might exceed 30 seconds — a report build, a batch import, a slow third-party call — Couchbase gives you no supported way to hold the lock through it.

  • There is no fencing token. Couchbase describes CAS as "an opaque 8 byte buffer" and warns that "it is wrong to assume that it is a simple counter value." That is the correct guidance for a CAS guard, and it also means CAS cannot be relied on as a monotonic fence. When a lock lapses because the holder stalled in a long GC pause rather than died, the resource it is protecting has no way to tell the revived holder from the current one, and no token to reject it with.

  • Locks are per-document only. There is no named lock, lease, semaphore, read/write lock or latch anywhere in the Couchbase Java SDK. Locking something that is not a document — a downstream API, a scheduled job, a shared file — means creating a placeholder document to lock, and inheriting the 30-second ceiling for it.

Redis has no lock API either, of course — SET NX PX and a Lua release script are the raw material. The difference is on the Java side, where Redisson ships the semantics rather than the primitives. RLock implements java.util.concurrent.locks.Lock and ships a watchdog that extends the lease in the background for as long as the holding process is alive:

RLock lock = redisson.getLock("catalog:rebuild");
lock.lock();
try {
    // no 30-second ceiling — the lease auto-renews while this thread holds it
    rebuildCatalogProjection();
} finally {
    lock.unlock();
}

For the stalled-holder case the watchdog cannot cover, RFencedLock returns a monotonically increasing token on each acquisition, which the guarded resource uses to reject a revived stale holder:

RFencedLock lock = redisson.getFencedLock("account:1042");
Long token = lock.tryLockAndGetToken(100, 10, TimeUnit.SECONDS);
if (token != null) {
    try {
        debitAccount(1042, amount, token);  // accepted only if token >= last seen
    } finally {
        lock.unlock();
    }
}

Beyond those, Redisson ships RReadWriteLock for read-heavy data, RFairLock for request-order acquisition, RSemaphore and RPermitExpirableSemaphore for limited-concurrency pools, RCountDownLatch for cross-JVM coordination, and a Redlock-style multi-lock. The Redis locks in Java guide and the locks and synchronizers documentation go through the semantics; distributed locks in Java covers the theory.

Cache-Shaped Data Structures

Caches are rarely all opaque blobs. You want a counter, a recent-items list, a set of permissions, a leaderboard. Both products offer Java collection types over their storage, and they are implemented very differently.

Couchbase's CouchbaseMap, CouchbaseArrayList, CouchbaseArraySet and CouchbaseQueue are, in the SDK's own description, "a client-side wrapper around the key-value and sub-document API," with each collection "backed by JSON documents stored in Couchbase Server." One collection is one document. That has three consequences.

First, the 20 MB item-size ceiling applies to the whole collection, not to an element. Second, the entire collection lives on one vBucket on one node, so a hot collection is a hot node. Third — and this is Couchbase warning you about its own API — CouchbaseMap carries a documented read-modify-write race:

The Map interface requires the 'put' and 'remove' methods to return the previous value associated with the key. To implement this behavior, CouchbaseMap needs to make at least 2 subdocument requests… If the document changes between these two requests, the code retries up to the casMismatchRetries limit, after which it gives up and throws an exception… There's also the potential for exceptions if concurrent map updates are extremely frequent.

The docs' own recommendation is to drop down to the Sub-Document API instead — it "will be a useful and possibly better alternative" to CouchbaseMap. That API is genuinely good — up to 16 operations per command, executed atomically against one document version, and "concurrent Sub-Document operations on different parts of a document will not conflict." It is just not a java.util.Map.

Redis puts the same operations on the server as single atomic commands. HSET, HDEL, ZADD, LPUSH, SADD and INCR need no retry loop because there is no read-modify-write cycle to lose. Redisson exposes them as Java collection typesRMap, RSet, RList and RQueue implement the JDK interfaces directly, with RScoredSortedSet and RAtomicLong alongside them — with no per-collection size ceiling beyond available memory, and with fastPut, fastPutIfAbsent and fastRemove variants that skip the return value entirely when you do not need the previous entry.

One asymmetry runs the other way. Because a Couchbase collection is a JSON document, you can query it with SQL++ and index it. A Redis hash is reachable by key and by the Redis Query Engine's secondary indexes, which is more than most people expect but still not a join.

Spring Boot: Genuinely Symmetric, Then Not

For the @Cacheable abstraction specifically, neither side has an integration advantage. Spring Boot auto-detects nine cache providers, and both are on the list in this order: Generic, JCache, Hazelcast, Infinispan, Couchbase, Redis, Caffeine, Cache2k, Simple. "If Spring Data Couchbase is available and Couchbase is configured, a CouchbaseCacheManager is auto-configured," exactly as "if Redis is available and configured, a RedisCacheManager is auto-configured." Both take cache names and a default expiry from properties:

spring:
  cache:
    cache-names: catalog,permissions
    couchbase:
      expiration: 10m
# and the Redis equivalent
#   redis:
#     time-to-live: 10m

Two footnotes on the Couchbase side. Its Spring Data reference notes that "to use cache.clear() or cache.invalidate(), the bucket must have a primary key" — clearing a cache is a SQL++ delete, not a keyspace operation, so it needs an index and it costs what a query costs. And the widely-linked couchbase-spring-cache artifact is not the thing to use: Spring Cache support "has been merged with spring-data-couchbase," and the standalone project is retired.

Where the symmetry ends is everywhere outside @Cacheable. Java caching is a family of standards and framework hooks, and Couchbase covers one of them.

Integration Couchbase Redisson

Spring Cache (@Cacheable)

Yes — auto-configured

Yes — RedissonSpringCacheManager

JCache (JSR-107)

No maintained provider

Yes — passes the JSR-107 TCK

Hibernate second-level cache

No official region factory

Yes

MyBatis cache

No official implementation

Yes

HTTP session store

No official Spring Session or Tomcat module

Spring Session and Tomcat

Near cache

None — the memory tier is server-side

RLocalCachedMap, plus local-cache variants of the above

The JCache row deserves a note, because a search will turn up couchbaselabs/couchbase-java-cache and it looks like an answer. It describes itself as "a work in progress JCache implementation for the Couchbase Java SDK 2.0" — a full major SDK version behind the current 3.12 line — and its own README lists pessimistic locking, write-through caching and expiration notifications among the pieces that are missing. It is not a production option.

The Tier Couchbase Does Not Have

Couchbase's memory-first design keeps data in RAM on the server. Every read is still a network round trip from your JVM. For a cache read at a few hundred microseconds that is fine; for a hot key read thousands of times a second it is pure overhead. You can put a Caffeine map in front of the SDK yourself, but nothing in Couchbase invalidates it when another node writes — the cross-JVM invalidation is the part you would be building.

Redisson's RLocalCachedMap keeps the hot subset inside the application process and invalidates it across the cluster when the shared copy changes:

// org.redisson.api.options.LocalCachedMapOptions — not the deprecated org.redisson.api.LocalCachedMapOptions.
// EvictionPolicy and SyncStrategy are nested enums on that class.
LocalCachedMapOptions<String, Product> options =
        LocalCachedMapOptions.<String, Product>name("catalog")
            .evictionPolicy(EvictionPolicy.LRU)
            .cacheSize(10_000)
            .syncStrategy(SyncStrategy.INVALIDATE)
            .timeToLive(Duration.ofMinutes(10));

RLocalCachedMap<String, Product> catalog = redisson.getLocalCachedMap(options);

Product p = catalog.get("sku-1042");   // served from JVM memory after the first read

The syncStrategy setting is what makes it safe: INVALIDATE drops the local copy on every node when an entry changes, UPDATE pushes the new value out instead. This is a genuine architectural option Couchbase does not offer, and it is the one that most changes read latency in practice. getLocalCachedMap is in the open-source edition; the local-cache variants of the Spring Cache, JCache, Hibernate and MyBatis integrations above are described by Redisson PRO as executing reads "up to 45x faster" and writes up to 4x faster.

Putting Redis in Front of Couchbase

Everything above assumes you are choosing between the two. Most teams reading this are not: Couchbase is already the system of record, and the second tier of work has arrived anyway — locks that outlive 30 seconds, rate limiters, a near cache, computed results that are not documents, TTL you can reason about to the second. The move then is not to replace Couchbase but to put a cache-aside or read-through layer in front of it. Redisson does that with a MapLoader so the cache-miss path disappears from your code:

// org.redisson.api.options.MapOptions — not the deprecated org.redisson.api.MapOptions

Cluster cluster = Cluster.connect("couchbase://127.0.0.1", "user", "pass");
com.couchbase.client.java.Collection products =
        cluster.bucket("catalog").defaultCollection();

MapLoader<String, Product> loader = new MapLoader<>() {
    @Override
    public Product load(String id) {
        try {
            return products.get(id).contentAs(Product.class);
        } catch (DocumentNotFoundException e) {
            return null;   // catch here — see the note below
        }
    }

    @Override
    public Iterable<String> loadAllKeys() {
        return cluster.query("SELECT RAW META().id FROM catalog._default._default")
                      .rowsAs(String.class);
    }
};

MapOptions<String, Product> options =
        MapOptions.<String, Product>name("product-cache").loader(loader);

RMap<String, Product> cache = redisson.getMap(options);

Product p = cache.get("sku-1042");   // Couchbase is read only on a miss

loadAllKeys() is used only for bulk preloading, and the SQL++ above needs a primary index on the keyspace — the same requirement that makes cache.clear() expensive on a Couchbase-backed Spring cache.

Two failure modes come with this shape, and both are covered in more depth in our DynamoDB write-up, where the same pattern applies: an exception thrown inside load() is swallowed and surfaces as null, indistinguishable from a document that does not exist, so a Couchbase timeout reaches your users as a 404 rather than a 500 unless you catch it there; and a read-through map couples read availability to cache availability, so decide the fallback deliberately rather than letting the whole fleet retry against the cluster at once. Java caching strategies covers the write side — write-through and write-behind through a MapWriter — and it is worth choosing a codec explicitly rather than inheriting the default, since every value crosses it twice.

Licensing, Sizing and the Cost of the Floor

Couchbase Server has been under the Business Source License 1.1 since March 2021. BSL permits production deployment but not "creating a commercial derivative work" or "offering or including it in a commercial product, application or service (e.g. commercial DBaaS, SaaS)." Each release carries its own Change Date on which it converts to Apache 2.0, and the clock restarts per release: Couchbase Server 7.0's date has passed, but Couchbase Server 8.0 does not become Apache 2.0 until 1 March 2029. The Java SDK is separate and genuinely open — com.couchbase.client:java-client is Apache 2.0, currently at 3.12.2, requiring Java 8 or later with Java 25 recommended.

Community Edition carries limits that a caching workload runs into early. The licence agreement prohibits deployment "in clusters comprised of more than five (5) node instances" and grants no rights to XDCR. The editions documentation adds the constraint most comparisons miss: "The Community Edition comes with limited concurrency and parallelism and supports a maximum of 4 cores per node." Five nodes at four cores is twenty usable cores cluster-wide, regardless of the hardware underneath — and the docs also note that Community Edition "does not include the latest bug fixes."

Then there is the floor. Couchbase documents a minimum of 4 GiB RAM per node and recommends 16 GiB or more, requires AVX2 on x86, and says it does "not recommend running a Couchbase Server deployment of less than three nodes in production." Capella's Enterprise tier has a three-node minimum starting from $0.49 per node-hour, with Basic from $0.15 and Developer Pro from $0.35 — US list prices as of September 2026, all of which scale with the vCPU and RAM allocated to each node. A cluster is also capped at 30 buckets, which is a real constraint if your instinct is one bucket per cache.

Redis and Valkey have no comparable floor. A cache tier can be one instance on a small box and grow into a sharded cluster when it needs to; Valkey is BSD-3-Clause with no edition tiering at all, and Redis 8 is available under AGPLv3 alongside its commercial licences. That does not make the second system free — sizing, patching, monitoring and failing over another datastore is the cost Couchbase's blog is right to name, and it is what you are trading against everything above. For teams weighing Couchbase alternatives for a cache tier specifically, rather than for a full document database, the licence question itself is covered in Redis alternatives.

Couchbase vs. Redis: How to Decide

If this is true… Choose

Couchbase is already your system of record and the working set fits the quota

Couchbase alone — do not add a second system for a problem you do not have

Cached data is far larger than affordable RAM and reads tolerate a disk fetch

Couchbase — a persistent bucket with value-only or full ejection; Redis Open Source and Valkey have no equivalent

You need to query cached data by fields, join it, or full-text search it

Couchbase — SQL++ over the cache is a real advantage

You are adding a cache tier in front of an existing database

Redis / Valkey — a three-node database is a heavy way to buy a cache, though an HA Redis tier is three to six nodes of its own

Your concurrency control is compare-and-swap on a single document

Couchbase — CAS comes back on every operation at no extra cost, and is cleaner than WATCH/MULTI

You need locks that outlive 30 seconds, fencing tokens, semaphores or rate limiters

Redis / Valkey with Redisson — Couchbase has no API for any of it

Your caching goes through JCache, Hibernate, MyBatis or a session store

Redis / Valkey — Couchbase covers Spring Cache and stops there

Read latency matters more than anything else

Redis / Valkey with a near cache — the round trip is the cost, and only a local tier removes it; Couchbase leaves the invalidation to you

Cache and durable state share one store and eviction must not touch the durable half

Redis / Valkey — the volatile-* policies exist for exactly this

The pattern across those rows is consistent. Couchbase's integrated cache is genuinely good at being a database that reads from memory. It is less good at being a cache, because the things that make a cache a cache — cheap deployment, per-key policy, coordination primitives, a local tier, and an ecosystem of framework hooks — are not what a database is optimized to provide. Couchbase's own engineers conceded the narrow version of this: for a pure cache, Redis performs very well. On the axis where Couchbase is structurally ahead — a working set larger than affordable RAM — it wins outright, and SQL++ over cached documents and per-operation CAS are advantages Redis has no equal for. What it does not have is the second tier: per-key eviction policy, a lock that outlives half a minute, a near cache, and the JCache, Hibernate, MyBatis and session hooks a Java cache tier gets wired into. Removing Memcached buckets did not change that; if anything it made the caching path in Couchbase less distinct from the database path, not more.

If you are weighing the same question against other stores, we have comparable write-ups for MongoDB, DynamoDB, Memcached and Hazelcast. For the implementation side of whichever you pick, start with distributed caching in Java and the cache API implementations documentation.

Couchbase vs. Redis: Frequently Asked Questions

Is Couchbase Faster Than Redis for Caching?

For a pure cache, Couchbase's own engineering blog concedes that Redis performs very well, and the Couchbase vs Redis performance numbers published by either vendor are marketing benchmarks rather than reproducible tests. The more useful difference is structural: every Couchbase read is a network round trip to a server-side memory tier, whereas a Redis deployment can add a near cache inside the JVM with Redisson's RLocalCachedMap and remove the round trip entirely for hot keys. Couchbase is faster in one specific case — when the working set is larger than available RAM, because a persistent bucket can serve part of the data from disk, which Redis Open Source and Valkey cannot do at all, and which Redis offers only in the commercial Redis Software and Redis Cloud tiers via Flex.

Can Couchbase Replace Redis as a Cache?

It can for straightforward key-value caching, especially if Couchbase is already your primary database. It cannot for the coordination work that usually accumulates around a cache. Couchbase's only pessimistic lock is a per-document getAndLock capped at 30 seconds with no renewal and no fencing token, and there is no named lock, semaphore, read/write lock or latch in the Java SDK. It also has no maintained JCache provider, no Hibernate second-level cache region factory, no MyBatis cache and no session store module.

What Happened to Couchbase Memcached Buckets?

They were deprecated in Couchbase Server 6.5.1 and fully removed in 8.0, released in October 2025. Cluster upgrades fail if Memcached buckets are present, so they must be removed first. The prescribed replacement is the Ephemeral bucket, which is also memory-only but adds rebalance, backup, query and eventing support. Note that Ephemeral buckets default to the noEviction policy, which returns an error on write when the bucket is full rather than evicting older entries — set nruEviction if you want cache-like behaviour. Redis defaults its maxmemory-policy to noeviction too, so the trap is shared; what differs is that Redis takes the change with one CONFIG SET.

Does Couchbase Support Spring Cache and @Cacheable?

Yes. Spring Boot auto-configures a CouchbaseCacheManager when Spring Data Couchbase is on the classpath and Couchbase is configured, with defaults set through spring.cache.couchbase.* properties. This is symmetric with Redis, which gets a RedisCacheManager the same way. Two caveats: clearing or invalidating a Couchbase cache is implemented as a SQL++ delete, so the bucket needs a primary index, and the standalone couchbase-spring-cache artifact is retired — the cache manager now ships inside spring-data-couchbase.

How Long Can You Lock a Document in Couchbase?

A maximum of 30 seconds, after which the server unlocks it automatically. Asking for longer does not clamp to the maximum — Couchbase documents that a lock request greater than 30 seconds causes the server to fall back to its default lock duration of 15 seconds instead. There is no renewal or extension operation in the Java SDK, so a critical section that may run longer cannot be protected this way. Redisson's RLock solves the same problem with a watchdog that extends the lease automatically while the holding process is alive.

Why Does My Couchbase Document Lose Its TTL After an Update?

Because Couchbase clears expiry on mutation by default. Its Java SDK documentation states that most operations will implicitly remove any existing expiration, and advises supplying the expiry value on every mutation. Since Couchbase Server 7.0 you can pass preserveExpiry(true) in the mutation options instead. Redis behaves the same way for SET and offers KEEPTTL as the equivalent opt-out, but its exposure is narrower: field-level operations such as HSET and INCR leave the key's timeout untouched, whereas any Couchbase document replace resets it.

Does Couchbase Reclaim Memory as Soon as a Document Expires?

No. Couchbase separates logical expiry from physical deletion. A read of an expired document immediately returns a not-found response, so correctness is unaffected, but the document keeps occupying RAM and counting toward the bucket's item count until the expiry pager runs, which is every 10 minutes by default, or until the document is accessed or auto-compaction runs. On a bucket sized close to its quota this matters, because expired-but-resident entries contribute to the eviction pressure that a cache is supposed to relieve.

Is Couchbase Open Source?

Partly. The Couchbase Java SDK is Apache 2.0. Couchbase Server itself has been under the Business Source License 1.1 since March 2021, which permits production use but not building a commercial derivative or offering it as part of a commercial service. Each release has its own Change Date on which it converts to Apache 2.0, and the clock restarts per release — Couchbase Server 8.0 converts on 1 March 2029. Community Edition is free but is capped at five nodes and four CPU cores per node, excludes XDCR, and does not include the latest bug fixes.