Skip to content

Compatibility & dependencies

Released minor versions preserve supported SDK behavior and persisted/wire contracts so applications can upgrade without rewriting their domain code.

However, you should always check the changelog for any breaking changes.

  • A newer Runtime accepts released workflows from older SDK versions.
  • A newer SDK works with an older Runtime while the application uses only protocol operations that Runtime supports.
  • A new SDK capability that needs a new Runtime operation fails explicitly as unsupported at its first request. It does not silently write a partial or legacy representation.

Upgrade the Runtime first before enabling a newly introduced Model protocol capability. Applications that do not use that capability remain compatible and can upgrade the two components independently within their supported release ranges. Upcasting is application-side SDK behavior; the Runtime neither executes nor replaces application upcasters.

Historical DOCUMENT-only Graph fallback uses the existing Model protocol, with expanded Runtime support for historical head-only metadata. The SDK can be upgraded first without changing its strict-property default. Current reads, writes and reconstructible histories retain their behavior. An older Runtime can still reject historical reads for which it cannot supply that metadata, as it did before the SDK upgrade. The new fallback becomes available after the Runtime update; no application setting or storage migration is required. See Historical Graphs and strict reads.

Compact Model-event reads accept historical MessagePack and binary message records within the same storage block, including compressed blocks. No application-side conversion or storage rewrite is required. This reader support does not remove the Runtime’s responsibility to serve compatible responses to older SDK clients.

The SDK advertises Fluxzero-Supports-Mixed-Model-Event-Blocks: true on every WebSocket connection. A compatible Runtime can pass mixed blocks directly to this reader; clients without this capability receive compatible responses prepared by the Runtime. Older runtimes may ignore the optional header.

The SDK uses ZSTD for default WebSocket compression and document serialization and requires a ZSTD-capable Runtime. Document and legacy message encoding uses bounds-checked Java array operations. Existing MessagePack storage and transport representations remain unchanged; applications need no migration or JVM-wide MessagePack property. The upstream MessagePack library is used only as a test reference and is no longer a transitive runtime dependency. Applications that directly use org.msgpack classes must declare org.msgpack:msgpack-core explicitly.

The SDK also reads historical LZ4 documents using bounds-checked Java compression and decompression, without Unsafe or native LZ4. SDK connections advertise Fluxzero-Supported-Document-Compression: ZSTD,LZ4,NONE, independently of outer WebSocket compression. A Runtime supporting this header preserves stored document bytes whenever the client supports their codec and converts only unsupported formats. No bulk storage migration is needed. Explicit LZ4, GZIP and NONE WebSocket configurations remain available. These compression defaults are not gated by fluxzero.defaults.version.

CompressionAlgorithm.LZ4 remains available in Java and Kotlin, with the same historical size-prefixed wire format. Fluxzero compression IDs remain NONE=0, LZ4=1 and ZSTD=2. The document MessagePack content and format identifier are unchanged. Direct reads of historical LZ4 blobs therefore remain supported. The LZ4 dependency remains included.

Clients without document capabilities or historical ZSTD support receive size-prefixed LZ4. Explicitly advertised codecs include support for their Fluxzero-framed envelopes; NONE documents use that envelope to identify uncompressed content. For unsupported stored codecs, Runtime selects ZSTD, then LZ4, then NONE from the client’s supported set. Transport compression preferences do not force document conversion. Custom document formats stay opaque.

For a mixed fleet, upgrade Runtime before introducing ZSTD document writes if any connected SDK cannot read ZSTD. Such an SDK needs the new Runtime conversion when reading documents written with ZSTD. An older Runtime cannot supply this new negotiation behavior merely because a newer producer is connected. Explicit document capabilities take precedence. Without them, advertised or selected ZSTD transport identifies older Java SDKs that already read Fluxzero-framed LZ4, ZSTD and NONE documents. Only without this support information does Runtime fall back to size-prefixed LZ4. Document writers retain the established size-prefixed LZ4 or Fluxzero-framed formats; ZSTD documents use the Fluxzero envelope.

Fluxzero SDK requires JDK 25 or higher to compile and run, including its common, test-server and proxy artifacts. Java and Kotlin projects must target JVM 25 or newer. SDK artifacts are compiled for Java 25, and the SDK build requires JDK 25.0.3 or newer before compilation to avoid the virtual-thread timer bug JDK-8370887. Use a maintained Java 25 patch for both Java and Kotlin applications. The SDK repository pins its development JDK in mise.toml; CI selects the latest Temurin 25 patch. No preview features are required. Builds on newer JDKs must keep maven.compiler.release=25 and the Kotlin JVM target at 25. Lombok 1.18.48 or newer is required when compiling on JDK 26 to avoid a runtime dependency from @SneakyThrows-generated code. This requirement does not change the Java baseline of the SDK 1.x release line.


DependencyScope
com.fasterxml.jackson.core:jackson-databindruntime
com.fasterxml.jackson.datatype:jackson-datatype-jsr310runtime
com.fasterxml.jackson.datatype:jackson-datatype-jdk8runtime
at.yawk.lz4:lz4-javaruntime
com.github.luben:zstd-jniruntime

Fluxzero includes its own SDK-focused Jakarta Validation implementation. Normal payload validation does not require Hibernate Validator, Expression Language, or their runtime dependencies.

DependencyScope
jakarta.validation:jakarta.validation-apicompile
DependencyScope
io.undertow:undertow-websockets-jsrruntime
io.jooby:joobyruntime

DependencyScope
org.springframework:spring-contextoptional
org.springframework:spring-testtest

Fluxzero provides full support for Kotlin, including:

  • Use of data classes, which behave like Java records
  • Optional types (e.g., String?) instead of @Nullable
  • Seamless use of Kotlin-specific language features (e.g., when, sealed class, companion object)
  • Support for Class<T> parameters passed as MyClass::class or MyClass::class.java
  • Automatic recognition of Kotlin modules during deserialization (see below)

Fluxzero includes Jackson Kotlin Module integration when available on the classpath. You do not need to manually register the module or use a service loader. If the jackson-module-kotlin dependency is present, it will be loaded dynamically for JSON (de)serialization.


DependencyScope
com.fasterxml.jackson.module:jackson-module-kotlinoptional
org.jetbrains.kotlin:kotlin-stdlib-jdk8optional
org.jetbrains.kotlin:kotlin-reflectoptional
org.jetbrains.kotlin:kotlin-testtest

DependencyScope
org.junit.jupiter:junit-jupiter-enginetest
org.junit.platform:junit-platform-launchertest
org.mockito:mockito-coretest
org.jooq:joortest
org.hamcrest:hamcrest-librarytest
org.jboss.resteasy:resteasy-undertowtest

ℹ️ Dependencies marked as optional are not required unless you use the corresponding integration. For example, Spring or Kotlin support is automatically detected when available but safely ignored otherwise.


Fluxzero aims to stay up-to-date with its core dependencies. We strive to:

  • Use the latest stable versions where possible,
  • Avoid breaking backward compatibility for common transitive consumers,
  • Update frequently, especially for frameworks like Jackson, Spring, Jakarta Validation, and JUnit.

KeyValueStore.store(...) and delete(...) now return CompletableFuture<Void>; storeIfAbsent(...) returns CompletableFuture<Boolean>. These methods do not block. This changes their binary signatures; recompile callers and update custom KeyValueStore implementations. Java callers needing the conditional result use store.storeIfAbsent(key, value).join(); Kotlin callers can likewise use .join() or await the future in a coroutine. The ordinary writes use DEFAULT, resolving to STORED in 2.x unless the application explicitly overrides it. storeIfAbsent always requests the stored Boolean result, independently of the default guarantee. For a dependency that must be durable before publishing, await store.store(key, value, Guarantee.STORED) first. The SDK’s data-protection writes and removals retain explicit durable completion. A tracking batch also awaits registered outgoing write futures before committing position; unrelated background work is outside that scope. SDK 1.x retains its synchronous key-value API and operation-specific guarantees.

The consumer option awaitSendAndForgetFutures is renamed to awaitOutgoingWrites in SDK 2.x. Update explicit Java/Kotlin @Consumer arguments, ConsumerConfiguration builder calls and accessors, then recompile applications and dependent libraries. The old name has no alias or fallback in 2.x; SDK 1.x keeps it. For an intentional opt-out, use @Consumer(name = "independent-writes", awaitOutgoingWrites = false) in either Java or Kotlin. Rebuild annotated handlers too: a previously compiled annotation using the old member does not configure the new one, so its old opt-out is ignored.

The default remains true: outgoing writes started within a tracked batch must reach their selected delivery guarantee before its position is committed. This rename does not change delivery guarantees or the separate awaitAsyncResults option for returned handler results. See Message tracking.


© 2026 Fluxzero