Bucket4j: Migration & What’s Changed
|
This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production. The reference material consulted while preparing these pages is listed in the section bibliography. |
Bucket4j keeps its API stable inside the 8.x line, so most upgrades are mechanical, but four things have moved enough to deserve
a page of their own: the bandwidth builder that replaced Bandwidth.simple and Refill in 8.5.0, the artifact names that
changed to bucket4j_jdk17- in 8.11.x, the *builder entry points (Bucket4jLettuce.casBasedBuilder and its relatives) that
replaced direct constructors, and the community Spring Boot starter, whose coordinates and supported modes changed between
its versions 0.13.0, 0.14.0 and 0.20.0-RC1. The page ends with every place where the official documentation disagrees with the code, gathered
from the whole Bucket4j part of this section so that you can see them in one table.
This is the one page of the section where deprecated API appears, and only as the "before" side of a migration. It was written against Bucket4j 8.21.0 (released on 2 October 2026), Spring Boot 4.1.x (4.1.1), Spring Framework 7.0.x and Java 21, with the community starter at 0.14.0 and 0.20.0-RC1 and Spring Cloud Gateway 5.0.3, and verified on 5 October 2026. Every Java example on this page, in its old and in its new form, was compiled and run against Bucket4j 8.21.0 in a scratch project, and a test proved that each old form behaves identically to its replacement on a manual clock. The vocabulary (capacity, refill, bandwidth) is in Token Bucket and Bandwidths; the Resilience4j counterpart of this page is Migration & What’s Changed.
Choosing a migration path
(JDK 11, groupId com.bucket4j)"] V1 --> B V -- no --> B{"8.0 to 8.4?"} B -- yes --> B1["8.5 builder
(Bucket4j class gone,
Bandwidth.builder)"] B1 --> A B -- no --> A{"Artifact named
bucket4j-core or bucket4j_jdk8-*?"} A -- yes --> A1["8.11.x rename
to bucket4j_jdk17-*
(needs Java 17)"] A1 --> D A -- no --> D{"Direct constructors or
build(key, config)?"} D -- yes --> D1["Builder entry points
and build(key, supplier)"] D1 --> ST D -- no --> ST{"Community Spring Boot
starter?"} ST -- yes --> ST1["0.12 to 0.13 to 0.14 to 0.20
(modules, no gateway filter)"] ST -- no --> DONE["Check the discrepancy table
before trusting the old docs"] ST1 --> DONE
Do the steps in this order. The artifact rename is a build change that does not touch your code, the bandwidth builder and the entry points are code changes that compile on every 8.x from 8.5.0 on, and the starter depends on the Bucket4j version it pins, so it comes last.
Source: Bucket4j: previous releases, with the release notes of each version linked in the
tables below, and Maven Central, bucket4j_jdk17-core
for the dates of publication.
7.x to 8.x
Bucket4j 7.0.0 was the release that redesigned the distributed facilities (a ProxyManager per backend, rolling upgrades,
non-JCache backends such as Redis and relational databases), and its release notes announce that the API it deprecated would be
removed "in 2023". The 8.x line then changed the platform rather than the model. The notes of 8.0.1 (31 July 2022) list the
migration to JDK 11 and the change of the Maven groupId to com.bucket4j; the Spring Boot starter’s own README dates the JDK 11
move to 8.0.0 and adds that the project then published dedicated Java 8 artifacts. Maven Central confirms the groupId move: the
7.x artifacts live under com.github.vladimir-bukhtoyarov, and the group com.bucket4j starts with 7.6.1 and 8.0.0.
<!-- Bucket4j 7.6.0 (JDK 8 baseline) -->
<dependency>
<groupId>com.github.vladimir-bukhtoyarov</groupId>
<artifactId>bucket4j-core</artifactId>
<version>7.6.0</version>
</dependency>
<!-- Bucket4j 8.0.0 to 8.10.1: new groupId, JDK 11 baseline -->
<dependency>
<groupId>com.bucket4j</groupId>
<artifactId>bucket4j-core</artifactId>
<version>8.10.1</version>
</dependency>
<!-- the same releases built for Java 8 -->
<dependency>
<groupId>com.bucket4j</groupId>
<artifactId>bucket4j_jdk8-core</artifactId>
<version>8.10.1</version>
</dependency>
Source: Bucket4j 8.0.1 release notes and
Bucket4j 7.0.0 release notes. The artifact versions were read from
maven-metadata.xml on Maven Central on 5 October 2026.
Inside 8.x the code that most often needs touching is the entry point of a local bucket. The utility class Bucket4j was
already @Deprecated in 7.6.0 and 8.4.0 (its methods delegate to the replacements) and is absent from 8.5.0, so code that still
calls it stops compiling on 8.21.0.
| Removed (7.x to 8.4.0) | Use instead (since 7.x, the only form from 8.5.0) |
|---|---|
|
|
|
|
The 8.21.0 source has no Bucket4j class; a test in the scratch project confirmed that Class.forName("io.github.bucket4j.Bucket4j")
throws ClassNotFoundException on 8.21.0. The changes that need no code, but that an upgrade across 8.x can meet, are in the
release notes. This table lists the ones with an effect on how a service is built or run.
| Release | Date | Change that can affect a migration |
|---|---|---|
31 July 2022 |
JDK 11 baseline, groupId |
|
5 March 2023 |
Redis Cluster support. Support for Spring Data Redis stopped: switch to the Lettuce, Jedis or Redisson integrations. JDBC integrations accept non-integer primary keys. |
|
2 May 2023 |
Key mapping on the |
|
2 October 2023 |
The builder API ("closer to the token-bucket description", #401). The next section. |
|
3 November 2023 |
The experimental |
|
12 November 2023 |
Microsoft SQL Server, |
|
24 February 2024 |
Request timeouts ( |
|
March 2024 |
Breaking: Hazelcast 3.x is no longer supported; the minimum is 4.1 since 8.10.0. |
|
24 April 2024 |
JDK 17, new artifact names, the Redis split and unified builders. Two sections below. |
|
1 May 2024 |
Cleaner of expired buckets for the relational databases ( |
|
7 June 2024 |
Fix of the batching optimization. |
|
18 August 2024 |
DB2. |
|
24 August 2025 |
MongoDB. The last release with |
|
2 February 2026 (8.16.0 on 28 December 2025) |
Valkey GLIDE, a retry strategy for compare-and-swap, OSGi metadata. |
Source: the previous-releases page with the release notes of each version, and the
GitHub releases for the exact dates. A release whose date is given only as a
month had no GitHub release; the month comes from Maven Central. 8.11.0 is the first version on Maven Central under the jdk17
names, and its content is described by the 8.11.1 notes.
The 8.5.0 bandwidth builder
Until 8.4.0 a bandwidth was created with a static factory: Bandwidth.simple(capacity, period) for a bucket that refills
completely every period, and Bandwidth.classic(capacity, Refill…) for everything else, with withInitialTokens and withId
as wither methods on the result. The factories are named after implementation details ("classic", "simple") rather than after the
two numbers of the token-bucket algorithm, and which Refill was greedy or intervally was a question of memorising factory names.
Release 8.5.0 (issue #401, "making the builder API to be more close with token-bucket description") added a staged builder:
Bandwidth.builder() then capacity, then one of four refill methods, then the optional id and initialTokens, then
build(). On a BucketConfiguration or Bucket builder, addLimit(limit → …) takes the same stages as a lambda. The old
factories, the withInitialTokens and withId methods and the whole Refill class were marked @Deprecated in 8.5.0; they still
work in 8.21.0, and under the project’s backward-compatibility policy deprecated API is removed only in a major release, so not
before 9.0.0. Version 9 has open milestones on GitHub and is not released.
| Before 8.5.0 (deprecated) | 8.5.0 and later |
|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Still valid; or |
The same mapping appears, next to the algorithm it describes, on Token Bucket and Bandwidths. The code below shows the two forms side by side. The first method is the "before"; it still compiles, with deprecation warnings.
Instant firstRefill = Instant.parse("2026-01-01T00:00:00Z");
Bandwidth[] before = {
Bandwidth.simple(100, Duration.ofMinutes(1)),
Bandwidth.classic(100, Refill.greedy(10, Duration.ofMinutes(1))),
Bandwidth.classic(100, Refill.intervally(10, Duration.ofMinutes(1))),
Bandwidth.classic(100, Refill.intervallyAligned(10, Duration.ofMinutes(1), firstRefill, false)),
Bandwidth.classic(100, Refill.intervallyAligned(10, Duration.ofMinutes(1), firstRefill, true)),
Bandwidth.classic(100, Refill.of(10, Duration.ofMinutes(1))).withInitialTokens(20).withId("plan")
};
Bucket bucket = Bucket.builder()
.addLimit(Bandwidth.classic(10, Refill.greedy(10, Duration.ofMinutes(1))))
.build();
Instant firstRefill = Instant.parse("2026-01-01T00:00:00Z");
Bandwidth[] after = {
Bandwidth.builder().capacity(100).refillGreedy(100, Duration.ofMinutes(1)).build(),
Bandwidth.builder().capacity(100).refillGreedy(10, Duration.ofMinutes(1)).build(),
Bandwidth.builder().capacity(100).refillIntervally(10, Duration.ofMinutes(1)).build(),
Bandwidth.builder().capacity(100).refillIntervallyAligned(10, Duration.ofMinutes(1), firstRefill).build(),
Bandwidth.builder().capacity(100)
.refillIntervallyAlignedWithAdaptiveInitialTokens(10, Duration.ofMinutes(1), firstRefill).build(),
Bandwidth.builder().capacity(100).refillGreedy(10, Duration.ofMinutes(1)).initialTokens(20).id("plan").build()
};
Bucket bucket = Bucket.builder()
.addLimit(limit -> limit.capacity(10).refillGreedy(10, Duration.ofMinutes(1)))
.build();
The test that accompanies this page asserted that each of the six before bandwidths is equals to the corresponding after
one, field by field (capacity, refill tokens and period, greedy or intervally, aligned time, adaptive initial tokens, initial
tokens and id), and that the two buckets give the same answers on a manual clock: with a capacity of 10 refilled 10 per minute,
the exhausted bucket reported exactly 6 seconds to wait, 5 tokens were back after 30 seconds, and 10 after five minutes, for both.
The intervally variant gave 0 tokens after 59 seconds and 10 after 60, for both.
Source: Bucket4j reference: Bandwidth,
Bucket4j reference: Refill types and the 8.21.0 source of
Bandwidth and
Refill, whose
@Deprecated tags are where the migration is announced. The 8.21.0 reference no longer shows the old factories at all (a search of
its page and of its AsciiDoc sources found no Bandwidth.simple, Bandwidth.classic or Refill.), so the deprecation is visible
only in the Javadoc and in your compiler’s warnings.
Two details of the builder are worth knowing before you convert code in bulk. initialTokens cannot be combined with
refillIntervallyAlignedWithAdaptiveInitialTokens (the builder throws), exactly as withInitialTokens could not be combined with
an adaptive Refill. And withNanosecondPrecision() belongs to the local bucket builder, not to the Bandwidth builder;
the aligned refills need a wall-clock time meter and refuse the nanosecond one.
Ids change what a replacement means
The builder makes it easy to add id("…") while you are converting. Do not add ids to an existing live configuration on the way:
replaceConfiguration with TokensInheritanceStrategy.PROPORTIONALLY matches the old and the new bandwidth by id (or by position
when neither has one). A run in the scratch project replaced capacity(20) (no id) by capacity(40)…id("plan") and the bucket
ended with 40 tokens, not the 30 that proportional inheritance gives, because the new bandwidth had an id the old one lacked and
was treated as a different bandwidth. With both ids unset the same replacement gave 30. See
Bandwidth ids decide which old
bandwidth is which.
MathType.IEEE_754 was removed in 8.6
Before 8.6 the MathType enum had a second, experimental value, IEEE_754, intended for testing backends written in Lua or
JavaScript that lack 64-bit integer arithmetic. The 8.5.0 source still has it and the 8.6.0 source does not (commit "#410 remove
experimental code", 24 October 2023, which the 8.6.0 tag contains). The 8.6.0 release notes do not mention it. On 8.21.0 MathType
is @Experimental and has one value, INTEGER_64_BITS, which a test of the scratch project asserted. Code that referred to
MathType.IEEE_754 has to be deleted; there is no replacement, and nothing in the 8.21.0 reference documents MathType.
Source: MathType at 8.21.0
and Bucket4j 8.6.0 release notes.
The distributed side: build(key, supplier) and the builder entry points
A ProxyManager hands out a BucketProxy for a key. The older way to pass the configuration was the BucketConfiguration itself:
proxyManager.builder().build(key, configuration). In 8.21.0 that overload is @Deprecated ("use build(Object, Supplier)
instead. This method will be removed soon" in the source). The replacement takes a Supplier<BucketConfiguration> that the
manager calls only when the bucket does not exist yet, which saves building a configuration on every request. The other change is
how the managers are created. The classes with public constructors (CaffeineProxyManager, InfinispanProxyManager and the JDBC
SQLProxyConfiguration family) are deprecated in favour of entry-point classes named Bucket4j<Backend>, whose static methods
return a builder that carries the client-side settings (clientClock, expirationAfterWrite, requestTimeout, maxRetries,
retryStrategy, executionStrategy and the others). The 8.11.1 release notes list "unified style builders for all ProxyManagers"
(#467).
The example uses the Caffeine backend because it needs no server: the old constructor keeps the buckets in a local cache, and its
keepAfterRefillDuration argument means "keep an entry for that long after the bucket has refilled completely", which is
ExpirationAfterWriteStrategy.basedOnTimeForRefillingBucketUpToMax(duration) in the new API.
ProxyManager<String> proxyManager = new CaffeineProxyManager<>(
Caffeine.newBuilder().maximumSize(10_000),
Duration.ofMinutes(1), // keep after refill
ClientSideConfig.getDefault().withClientClock(clock));
BucketConfiguration configuration = BucketConfiguration.builder()
.addLimit(Bandwidth.simple(100, Duration.ofMinutes(1)))
.build();
BucketProxy bucket = proxyManager.builder().build("client-1", configuration);
ProxyManager<String> proxyManager = Bucket4jCaffeine
.<String>builderFor(Caffeine.newBuilder().maximumSize(10_000))
.expirationAfterWrite(ExpirationAfterWriteStrategy
.basedOnTimeForRefillingBucketUpToMax(Duration.ofMinutes(1)))
.clientClock(clock)
.build();
BucketConfiguration configuration = BucketConfiguration.builder()
.addLimit(limit -> limit.capacity(100).refillGreedy(100, Duration.ofMinutes(1)))
.build();
BucketProxy bucket = proxyManager.builder().build("client-1", () -> configuration);
// or, when the supplier is all you need:
BucketProxy same = proxyManager.getProxy("client-1", () -> configuration);
In the test both managers were given a manual TimeMeter as clock. After consuming 70 of 100 tokens both proxies reported 30
available, and after 30 simulated seconds both reported 80. getProxy(key, supplier) returned a proxy over the same bucket as
builder().build(key, supplier): a second proxy for the same key was refused a token that the first had taken. The constructors
are @Deprecated in the 8.21.0 source (a reflection check in the test confirmed it for the two-argument CaffeineProxyManager
constructor and for RemoteBucketBuilder.build(Object, BucketConfiguration)).
Source: Bucket4j reference: ProxyManager and the 8.21.0 source of
Bucket4jCaffeine,
RemoteBucketBuilder
and AbstractProxyManagerBuilder.
The backend-by-backend entry points and what each requires are on Bucket4j backends,
and the settings of the builder on
distributed rate limiting.
8.11.1: JDK 17 and the artifact rename
The 8.11.1 release notes list three items: split Redis support into individual Maven modules (#466), unified builders (#467) and
the migration to JDK 17 (#474). Under "Backward incompatible changes" they say that the target JDK is now part of the artifact
name: com.bucket4j:bucket4j-core became com.bucket4j:bucket4j_jdk17-core, and that the Redis dependencies were split into
the Jedis, Lettuce and Redisson modules. On Maven Central bucket4j_jdk17- starts at 8.11.0 (the GitHub release 8.11.0 is dated 24 April 2024)
and the notes are filed under 8.11.1. Because the *artifactId changes, a dependency bot that follows
bucket4j-core never sees the new releases: the legacy bucket4j-core ends at 8.10.1 on Maven Central.
| Artifact ids | Versions on Maven Central | Notes |
|---|---|---|
|
8.11.0 to 8.21.0 |
Current line. Java 17 or later. |
|
8.11.0 to 8.15.0 |
Last built in August 2025. Nothing newer exists, although the project’s compatibility policy still promises JDK 11 artifacts. |
|
8.0.0 to 8.10.1 |
Last published in March 2024. Later Java 8 builds are commercial only. |
|
7.6.1, 8.0.0 to 8.10.1 |
The names used before the rename; the Redis integration is a single |
<dependency>
<groupId>com.bucket4j</groupId>
<artifactId>bucket4j-core</artifactId>
<version>8.10.1</version>
</dependency>
<dependency>
<groupId>com.bucket4j</groupId>
<artifactId>bucket4j-redis</artifactId>
<version>8.10.1</version>
</dependency>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.bucket4j</groupId>
<artifactId>bucket4j_jdk17-bom</artifactId>
<version>8.21.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.bucket4j</groupId>
<artifactId>bucket4j_jdk17-core</artifactId>
</dependency>
<dependency>
<groupId>com.bucket4j</groupId>
<artifactId>bucket4j_jdk17-redis-common</artifactId>
</dependency>
<dependency>
<groupId>com.bucket4j</groupId>
<artifactId>bucket4j_jdk17-lettuce</artifactId>
</dependency>
</dependencies>
The Redis rule is that one redis-common and exactly one client module (lettuce, jedis, redisson, and from 8.16 and 8.17
glide and vertx) replace the single legacy artifact. The aggregator bucket4j_jdk17-redis stopped at 8.14.0 and is not a
dependency to use. If your runtime is Java 11, 8.15.0 is the newest release you can run, with the bucket4j_jdk11- ids, and the
Java 8 route is the commercial one. The project’s java-compatibility-matrix.md still shows the legacy names for JDK 11
(bucket4j-core) and bucket4j_jdk8- for Java 8, so it predates the rename; the table above is the Maven Central truth.
Source: Bucket4j 8.11.1 release notes,
Bucket4j reference: Adding the Bucket4j dependency and the
bucket4j-bom module at 8.21.0. The artifact table was
built from the maven-metadata.xml files of Maven Central. The Maven history is also on
the overview page.
From 8.16 to 8.21: new entry points and modules
Since 8.16 the releases have added backends and one build tool, not new concepts. Every new module follows the entry-point rule of
the previous section: a Bucket4j<Backend> class with static builder methods, no public constructor to learn. The versions below
are the first on Maven Central, cross-checked against the release notes.
| Release | Module (artifact bucket4j_jdk17-…) |
Entry point and notes |
|---|---|---|
8.16.x |
|
|
8.17.0 |
|
|
8.18.0 |
|
|
8.19.0 |
core |
The compare-and-swap retry mechanism (#580). In 8.21.0 the builders expose it as |
8.20.0 |
|
|
8.21.0 |
|
|
8.21.0 |
|
|
8.21.0 |
|
|
8.21.0 |
|
Dedicated modules for the older majors: |
8.21.0 |
|
|
8.21.0 |
core |
Serialization moved from byte-array streams to |
Two facts from this list matter at upgrade time. The redis, hazelcast-all and infinispan-all aggregator artifacts have no
8.21.0 build, so a dependency on one of them freezes at 8.14.0; use the individual modules. And the release notes of 8.20.0
and 8.21.0 repeat the items of earlier releases (#580, #588, #615, #595 and #606 appear in both), so read them as a running list and
not as a per-release diff; the Maven Central versions are the reliable record of which module arrived when.
The following code shows what a new-style entry point looks like in a service and compiles on 8.21.0 with only the Caffeine module on the classpath; the other entry points above have the same shape and differ in the client object they take.
ProxyManager<String> proxyManager = Bucket4jCaffeine
.<String>builderFor(Caffeine.newBuilder().maximumSize(10_000))
.expirationAfterWrite(ExpirationAfterWriteStrategy
.basedOnTimeForRefillingBucketUpToMax(Duration.ofMinutes(5)))
.build();
Supplier<BucketConfiguration> freePlan = () -> BucketConfiguration.builder()
.addLimit(limit -> limit.capacity(20).refillGreedy(20, Duration.ofMinutes(1)))
.build();
BucketProxy bucket = proxyManager.getProxy("api:alice", freePlan);
boolean allowed = bucket.tryConsume(1);
Source: Bucket4j 8.21.0 release notes, 8.20.0, 8.19.0, 8.18.0, 8.17.0 and 8.16.1, the entry-point classes in the 8.21.0 source tree, and Bucket4j reference: ProxyManager.
The community starter: 0.12, 0.13, 0.14 and 0.20
The Spring Boot starter described on its own page is a community project
and has its own release line. Its README carries a migration guide, which this section reads together with the poms and sources of
the tags 0.13.0, 0.14.0 and 0.20.0-RC1. The facts that matter for a migration:
| Starter | Spring Boot | Bucket4j | Layout | What changed |
|---|---|---|---|---|
0.12.x |
3.2 to 3.4 |
8.9.0 to 8.10.x |
one starter |
The removed |
0.13.0 |
3.5.0 |
8.14.0 |
|
Bucket4j dependencies carry |
0.14.0 |
4.0.3 |
8.15.0 |
|
Spring Boot 4. The README says "Spring Gateway Support dropped" here, but the 0.14.0 source still has |
0.20.0-RC1 |
4.1.1 |
8.17.0 |
|
Restructured modules with explicit dependencies per use case. |
No 0.20.0 GA exists on Maven Central: bucket4j-spring-boot-starter stops at 0.14.0, the new artifacts list 0.20.0-RC1 as their
only version, and the GitHub releases page marks 0.14.0 as the latest. On Spring Boot 4.1 the starter is therefore a release
candidate, on Spring Boot 4.0 it is 0.14.0 and on Spring Boot 3.5 it is 0.13.0; check again before you adopt, because the
coordinates of a GA may differ from the RC. The README of 0.20.0-RC1 contradicts the sources on two points that matter here: its
version list says "0.14.0 - Spring Gateway Support dropped" (the Gateway filter went in 0.20.0-RC1) and "0.20.0 - Bucket4j 8.16.x -
Spring Boot 4.0.0" (the pom has Bucket4j 8.17.0 and Spring Boot 4.1.1).
Dependencies: from one starter to feature and cache modules
With 0.14.0 an application declared the starter and the third-party library of its cache; the starter brought Bucket4j core and
the JCache module itself. With 0.20.0-RC1 the application picks a feature module (starter-servlet, starter-webflux,
starter-aop) and a cache module, in the group com.giffing.bucket4j.spring.boot.starter. starter-servlet and starter-webflux
cannot be on the same classpath. The starter pins Bucket4j 8.17.0, so import the Bucket4j BOM to move every jar to 8.21.0.
<dependency>
<groupId>com.giffing.bucket4j.spring.boot.starter</groupId>
<artifactId>bucket4j-spring-boot-starter</artifactId>
<version>0.14.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>jcache</artifactId>
<version>3.2.4</version>
</dependency>
<dependencyManagement>
<dependencies>
<!-- the starter pins Bucket4j 8.17.0; this moves every Bucket4j jar to 8.21.0 -->
<dependency>
<groupId>com.bucket4j</groupId>
<artifactId>bucket4j_jdk17-bom</artifactId>
<version>8.21.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>com.giffing.bucket4j.spring.boot.starter</groupId>
<artifactId>starter-servlet</artifactId>
<version>0.20.0-RC1</version>
</dependency>
<dependency>
<groupId>com.giffing.bucket4j.spring.boot.starter</groupId>
<artifactId>cache-jcache</artifactId>
<version>0.20.0-RC1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>jcache</artifactId>
<version>3.2.4</version>
</dependency>
</dependencies>
Method-level limits add starter-aop and, on Spring Boot 4, spring-boot-starter-aspectj: the spring-boot-starter-aop that the
README names does not exist in Boot 4. The module list, the cache-to-use value of each cache module and the beans each one needs
are in the starter page.
Source: starter README: Migration guide and the
0.20.0-RC1 tag, whose pom.xml files give the module
list, with the poms of the tags 0.13.0 and 0.14.0 for the earlier layout and versions.
YAML: what changes and what does not
The property model is stable across the three Boot-4-era versions. The same filter YAML bound and limited identically on 0.14.0
(Spring Boot 4.0.3) and on 0.20.0-RC1 (Spring Boot 4.1.1) in the scratch project of this section, and the property classes of the
two tags have the same keys and defaults for bucket4j.filters[], rate-limits[] and bandwidths[]. What changes is a mode that
disappears and one property that was removed earlier.
bucket4j:
enabled: true
filters:
- id: gateway-books
cache-name: buckets
filter-method: gateway # FilterMethod.GATEWAY exists in 0.13.0 and 0.14.0
url: /api/.*
rate-limits:
- cache-key: "getRemoteAddr()"
bandwidths:
- capacity: 100
time: 1
unit: minutes
bucket4j:
enabled: true
cache-to-use: jcache
filters:
- id: servlet-books
cache-name: buckets
filter-method: servlet # SERVLET, WEBFLUX and JMS are the values left
url: /api/.*
rate-limits:
- cache-key: "getRemoteAddr()"
bandwidths:
- capacity: 100
time: 1
unit: minutes
On a Spring Cloud Gateway application there is no replacement inside the starter: filter-method: gateway no longer binds on
the 0.20.0-RC1 tag and the Gateway filter factory is gone. The supported route is the gateway’s own limiter, which uses Bucket4j directly,
described on Bucket4j in Spring Cloud Gateway. And the removed
expression property, which the README’s 0.12 entry names, is a plain rename:
# before 0.12 (the property is removed, not just deprecated)
bucket4j:
filters:
- cache-name: buckets
url: /api/.*
rate-limits:
- expression: "getRemoteAddr()"
bandwidths:
- capacity: 100
time: 1
unit: minutes
# 0.12 and later
bucket4j:
filters:
- cache-name: buckets
url: /api/.*
rate-limits:
- cache-key: "getRemoteAddr()"
bandwidths:
- capacity: 100
time: 1
unit: minutes
All key names in these three YAML blocks were checked against the property classes of the 0.20.0-RC1 tag
(Bucket4JConfiguration, RateLimit, BandWidth) and, for filter-method: gateway, against the FilterMethod enum of 0.14.0,
which has SERVLET, WEBFLUX, GATEWAY and JMS, where the 0.20.0-RC1 enum has no GATEWAY. A neighbouring expression
exists only on the metric tags (MetricTag), a different property. The starter also needs a Bean Validation provider
(spring-boot-starter-validation), because it validates its properties at startup.
Source: starter README: Bucket4j complete properties
and the FilterMethod, Bucket4JConfiguration and RateLimit classes of the
0.20.0-RC1 tag.
The full discrepancy table
Official documentation drifts from code. This is the list of places where the Bucket4j reference, the Javadoc, the project README and release notes, the community starter’s README and the Spring Cloud Gateway reference disagree with what the code does, checked against Bucket4j 8.21.0, the starter tags and Spring Cloud Gateway 5.0.3 on 4 and 5 October 2026. Each row names the page of this section where the topic is explained with a working example. Where the reference is stale, the row links the the 8.21.0 source file or the release notes that show the real behaviour; the links to the reference itself are in the page that the last column names.
| Topic | Official docs say | 8.21.0 (starter, gateway) behaviour | Covered on |
|---|---|---|---|
Bucket4j: deprecated |
The 8.21.0 reference no longer shows them (zero occurrences in its page and AsciiDoc sources). The 8.5.0 release notes say only "builder API closer to the token-bucket description" and do not list the deprecations. |
Deprecated since 8.5.0 in the source ( |
Token bucket, this page |
Bucket4j: |
Shown once in the reference (technical limitations, the refill-period example) and in the Javadoc of |
There is no such overload: only the no-argument |
|
Bucket4j: custom |
|
|
|
Bucket4j: |
Shown on |
Does not exist on the 8.21.0 builders (it survives on the deprecated |
|
Bucket4j: |
The Javadoc of the supplier overload says it has "the same semantic" as |
The |
Distributed rate limiting, this page |
Bucket4j: Infinispan Hot Rod example |
The variable is typed |
|
|
Bucket4j: asynchronous servlet example |
|
The constructors are |
|
Bucket4j: REST filter and JCache servlet examples |
|
Spring Boot 4 (Jakarta EE 11) uses |
|
Bucket4j: |
Older descriptions and examples imply a blocking |
|
|
Bucket4j: proxy-manager optimizations |
Not in the reference. |
|
|
Bucket4j: Caffeine module |
The reference mentions Caffeine nowhere; the README links the |
|
Backends, this page |
Bucket4j: |
Not documented in the reference. |
|
Bucket API, this page |
Bucket4j: clock skew between replicas |
Not mentioned for compare-and-swap, lock and select-for-update backends. |
The application JVM’s clock is used unless |
|
Bucket4j: Micrometer example (the reference’s listener example) |
|
Bucket4j has no built-in Micrometer integration; the example works with |
|
Bucket4j: the distributed checklist and expiry |
The retention item names Ignite and Ignite 3 as the backends without per-entry expiration. |
The 8.21.0 builders also refuse an |
|
Bucket4j: dependency snippet |
A plain dependency with a version, no BOM. |
|
Overview, this page |
Bucket4j: JDK 11 artifacts and the compatibility policy |
The backward-compatibility policy promises Maven Central artifacts for two LTS JDKs (17 and 11); the compatibility matrix lists |
|
Overview, this page |
Bucket4j: link "Java compatibility matrix" (quick start) |
The reference links the "Java compatibility matrix" for a Java 8 build. |
The link leads to the commercial Java 8 page, not to the repository matrix. Open-source Java 8 artifacts end at 8.10.1. |
|
Bucket4j: DynamoDB |
The 8.7.0 release notes list "support for Amazon DynamoDB has been removed"; the reference has no section on it. |
No DynamoDB module in the 8.21.0 repository; |
|
Bucket4j: Infinispan 16 in the 8.21.0 notes |
"Support for Infinispan 16.x via a dedicated module". |
The new dedicated module is |
Backends, this page |
Bucket4j: release notes of 8.5.0, 8.6.0, 8.20.0 and 8.21.0 |
8.5.0 lists only the builder; 8.6.0 lists only a |
The 8.5.0 deprecations and the 8.6.0 removal of |
This page |
Bucket4j README at the 8.21.0 tag |
The dependency snippet and the documentation links show 8.20.0 and |
The documentation lives at |
This page |
Starter README: Maven coordinates |
XML examples use the artifact ids |
Maven Central has |
|
Starter README: |
|
|
|
Starter README: version list |
|
The 0.20.0-RC1 parent pom has Spring Boot 4.1.1 and Bucket4j 8.17.0. No GA 0.20.0 exists on Maven Central. |
|
Starter README: |
Lists "jcache, hazelcast, ignite, redis", and the cache table names |
The values are |
|
Starter README: |
The properties example writes |
The property is the singular |
|
Starter README: |
The method example uses |
The enum constant is |
|
Starter README: |
It adds the method name to the key. |
Nothing reads the attribute in 0.13.0, 0.14.0 or 0.20.0-RC1; the key always starts with the method name, so overloads share a bucket. |
|
Starter README: |
"Does not affect custom headers" (also the property’s Javadoc). |
The servlet and WebFlux filters hide the custom |
|
Starter README: |
A property of the filter metrics. |
It is never read; use |
|
Starter README: |
Method dependencies: add |
That starter does not exist in Spring Boot 4; AspectJ comes from |
|
Starter README: |
"Set it to a number higher than zero to run after Spring Security." |
The default is |
|
Gateway docs: Caffeine example |
|
Both |
|
Gateway docs: Bucket4j version link |
The reference links the Bucket4j 8.7.0 documentation. |
The documentation of the version you use is at |
|
Gateway docs: |
The WebFlux section spells the type with a typo. |
The type is |
|
Gateway docs: "Spring Cloud Gateway manages Bucket4j 8.15.0" |
Read as "the gateway sets the Bucket4j version". |
True only of the gateway’s own build: |
|
Gateway docs: |
|
The code binds |
|
Gateway docs: |
|
The refill period is whatever |
The table has 39 rows, and it gathers what the rest of the Bucket4j part of this section states in prose. When the reference, a README or a documentation page and one of these rows disagree, trust the 8.21.0 source files linked in the row, or the source of the starter and gateway tag named in it, and treat the official page as a good description of the concept rather than of the signature.
Source: Bucket4j reference: Technical limitations, Bucket4j reference: Client-side configuration, Bucket4j reference: Infinispan, Bucket4j reference: Asynchronous API, Bucket4j reference: Limiting the rate of access to a REST API, Bucket4j reference: Custom time measurement strategy, Bucket4j reference: Generic production checklist and the starter README; the Spring Cloud Gateway pages are in the Spring Cloud Gateway reference.
Pitfalls
| Pitfall | What happens | What to do |
|---|---|---|
A dependency bot that follows |
It never proposes anything newer than 8.10.1, because the artifact id changed in 8.11.x |
Switch to |
Both |
Duplicate |
Exclude the legacy artifact from every transitive dependency (an old starter, an internal library) |
Staying on Java 11 and bumping to 8.21.0 |
The jars need Java 17 |
Stay on |
|
The class is gone since 8.5.0: a compile error |
|
Converting |
|
Use |
Adding |
|
Give both the old and the new bandwidth the same id, or none |
Declaring the aggregators |
The newest build is 8.14.0, with no 8.21.0 |
Use the individual modules and the BOM |
Starter 0.20.0-RC1 keeps Bucket4j 8.17.0 |
Fixes and modules of 8.18 to 8.21 are missing |
Import |
|
They cannot share a classpath |
One feature module per application |
|
The value no longer binds and the Gateway filter is gone |
Use the gateway’s native Bucket4j limiter |
Following a reference example that does not compile |
|
Use the discrepancy table above |
What changed
-
7.x to 8.0: JDK 11 baseline, groupId
com.bucket4j, dedicatedbucket4j_jdk8-*artifacts for Java 8. -
8.5.0: the
Bandwidth.builder()andaddLimit(limit → …)API;Bandwidth.simple,Bandwidth.classic,withInitialTokens,withIdand theRefillclass are deprecated; theBucket4jfactory class is gone. -
8.6.0:
MathType.IEEE_754removed. -
8.7.0: Amazon DynamoDB support removed.
-
8.11.x:
bucket4j_jdk17-*artifacts, Redis split intoredis-commonplus a client, unified builders for everyProxyManager. -
8.15.0: the last
bucket4j_jdk11-*release. -
8.16 to 8.21: GLIDE, Vert.x, Couchbase, Geode, Memcached, Cassandra, Ignite 3,
infinispan-15andcoherence-21, the compare-and-swap retry mechanism, Redis Sentinel through Lettuce, and in 8.21.0 thebucket4j_jdk17-bom. -
Starter: 0.13.0 on the
jdk17artifacts, 0.14.0 on Spring Boot 4, 0.20.0-RC1 on the new module layout without the Gateway filter; no GA 0.20.0 yet. -
Version 9: not released; the policy removes deprecated API only in a major release, so everything on this page that avoids deprecated API should carry over. The state of the line is on the previous-releases page.