KurrentDB 25.1: Secondary Indexes and Multi-Stream Appends

We have release KurrentDB 25.1 with exciting new features that enable more flexible data access patterns, mitigate the need for projections, and allow atomic write operation that go beyond the scope of a single stream.

Packages are there, docs updated, all set :slight_smile:

Here’s the full announcement: KurrentDB 25.1: Secondary Indexes and Multi-Stream Appends

1 Like

Wow, finally! The Multi-Stream Appends feature is really helpful.
I have just one question and a clarification request.

I noticed that appending more than one event to the same stream within a single multi-stream append session is currently not supported. It fails with the following error:

"Stream 'stream-name' is already part of this append session. Appending to the same stream multiple times is currently not supported."

Does this mean this is a temporary limitation and that support for multiple appends to the same stream within the same session is planned for the future? Is there any rough timeline or design direction already in mind?

I understand the comment in the code:

// *** Temporary limitation ***
// We do not allow appending to the same stream multiple times in a single append session.
// This is to prevent complexity around expected revisions and ordering of events.
// In the future, we can consider relaxing this limitation if there is a valid use case.
// For now, we keep it simple and safe.

I believe there are strong and concrete use cases for relaxing this limitation.

Example use case
Consider a complex transactional workflow between actor-like components (for example aggregates or grains) where:

  • A first event on a stream establishes the validity of the operation (expected revision check).
  • Subsequent domain decisions, possibly involving back-and-forth interactions, result in additional events that must be atomically appended as part of the same logical transaction.

In this scenario, the first append already resolves and validates the stream revision. For subsequent appends to the same stream, it should be possible to:

  • Accept StreamState.Any, or
  • Validate against the resolved revision of the first event plus the offset of the subsequent events.

Alternatively, a constrained option such as something like StreamRevision.Subsequent (only valid after the first append in the same session) could already unlock many powerful scenarios while keeping the rules simple.

This would enable much more expressive and “worry-free” transactional flows, especially when modeling complex domain logic without having to artificially merge multiple domain events into a single event just to fit the current constraint.

Am I missing some deeper complication here, for example related to index maintenance or ordering guarantees?
If this is an area where community contributions could help, I would be happy to get involved.

2 Likes

Hm, I was not aware of this. It should have been done. Let me check internally.

Ok I checked. You can append multiple events to the same stream in one session but they need to be adjacent. Let’s say you have a stream A and a stream B. You can append:

  • AB
  • BA
  • AAB
  • ABB
  • AABB
  • etc

But you cannot append

  • ABA
  • BAB
  • BAAB
  • etc

It’s quite easy to overcome the current limitation by collecting events on the client side somehow, and then grouping them by stream name when creating the append session. We will make it easier at some point, it requires some work on the edge though.

1 Like

Btw there’s a critical MSA bug in 25.1.0 and it’s fixed in 25.1.1/2

Thank you very much for the clarification, that makes sense.

Yes, grouping events by stream on the client side is definitely an easy workaround.

That said, I am still wondering whether there is any chance that interleaving patterns like the ABA case you mentioned could be supported in the future, and whether this would be particularly difficult to implement.

In my use case, preserving the global ordering of events across streams can be very valuable, especially to make cause–effect chains explicit. It helps both with reasoning about complex flows and with debugging advanced scenarios.

From this point of view, allowing interleaving would be quite powerful.

I understand that, since all these events are committed as part of a single atomic operation, they logically “happen together”, so one could argue that the lobal order is less important. However, in practice, preserving the original order can still matter, for example:

  • when projections consume events from multiple streams and rely on their relative ordering;

  • when analyzing or replaying event sequences to understand cross-stream interactions.

In these cases, reordering events by stream before appending may alter the perceived causality between events.

If interleaving is fundamentally problematic, is there any recommended mechanism to explicitly record such cross-stream dependencies or causal relationships?

Additionally, I tested the 25.1.1 Docker image (i wans’t able to find the 25.1.2 at the moment of writing) and I am still seeing the same exception, even with a simple AA pattern:


Status(StatusCode="Aborted", Detail="Stream 'A' is already part of this append session. Appending to the same stream multiple times is currently not supported.)

This made me wonder whether the adjacent-append behavior is already available in 25.1.1 or if it is planned for a later patch.

3 Likes

It should work with 25.1.0 and any patches for that version. I will check internally what could be the reason for this error you see apart from what we discussed.

Hey @duke! interleaving multi-stream appends across streams is feasible but let us talk internally to see how and when we can accomplish this.

That would be truly AMAZING! let me know if i can help somehow.

1 Like

Looking at the source code there is an interesting test that already pass, called

MultiStreamWritesTests.succeeds_with_aba_pattern

which for my understanding is exactly testing that is possible to perform multi stream transactions with interleaved streams (and even more complex scenarios).

so it should be already available!

StreamsService.AppendSession (rows 80-87) → blocks duplicate streams (the exception i’ve reported)

if this was not throwing the flow proceed with

StreamsService.BuildMessage (row 107) → creates ClientMessage.cs WriteEvents
↓
SAME CODE used by the succeeds_with_aba_pattern test

If i get it right this should prove that the core of the db already support this scenario, and the exception thrown is artificial and unnecessary: can it be fixed in the next release please?