> ## Documentation Index
> Fetch the complete documentation index at: https://docs.flowwarden.io/llms.txt
> Use this file to discover all available pages before exploring further.

# FAQ

> Common technical questions about prerequisites, operations, and how FlowWarden compares to alternative stream-processing tools

This page answers the most common technical questions about running FlowWarden in production and how it positions against other stream-processing options. For full coverage of any topic, follow the linked guide.

***

## Compatibility & prerequisites

<AccordionGroup>
  <Accordion title="Which Java, Spring Boot, and MongoDB versions are required?" icon="java">
    FlowWarden requires **Java 17+**, **Spring Boot 3.x**, and **MongoDB 6.0+ running as a Replica Set**. Both Spring MVC and Spring WebFlux are supported.

    Virtual threads (Project Loom) are supported on Spring Boot 3.2+ — see the [threading guide](/guides/threading-and-scaling) for the caveats.

    See the [Quickstart](/quickstart) for the full setup.
  </Accordion>

  <Accordion title="Does FlowWarden work with a MongoDB standalone or a sharded cluster?" icon="database">
    **Standalone is not supported.** MongoDB Change Streams require a Replica Set — this is a MongoDB API constraint, not a FlowWarden limitation. For local development, a single-node Replica Set (`--replSet rs0`) is enough.

    Sharded clusters work with MongoDB Change Streams natively. FlowWarden's `SINGLE_LEADER` mode uses a single distributed lock per stream, so it remains correct across shards.
  </Accordion>

  <Accordion title="Can I use FlowWarden with Spring WebFlux / reactive code?" icon="bolt">
    Yes. Set `flowwarden.default-mode: REACTIVE` in `application.yml` and write handlers that return `Mono<Void>`. The runtime uses `ReactiveMongoTemplate` and Project Reactor's `concatMap` to preserve per-stream ordering.

    See [Imperative vs Reactive](/guides/imperative-vs-reactive) for the decision criteria.
  </Accordion>
</AccordionGroup>

***

## Operations & scaling

<AccordionGroup>
  <Accordion title="What is the difference between SINGLE_LEADER and ALL_INSTANCES? Which one should I pick?" icon="server">
    * **`ALL_INSTANCES`** (default) — every application instance processes every event. Use for cache invalidation, local read-models, and any handler whose effect is idempotent and local.
    * **`SINGLE_LEADER`** — only one instance (the leader) processes events; others stand by. Use for non-idempotent side effects: billing, emails, payments, order processing.

    | Aspect               | `ALL_INSTANCES` | `SINGLE_LEADER` |
    | -------------------- | --------------- | --------------- |
    | Duplicates           | Yes             | No              |
    | Failover delay       | None            | \~20–80s        |
    | Idempotency required | Yes             | No              |

    Full details and timing parameters in [Deployment Modes](/guides/deployment-modes).
  </Accordion>

  <Accordion title="What happens if the leader instance crashes? Is there a risk of double processing?" icon="shield-halved">
    Leader election relies on a MongoDB lock with a **60-second TTL**, renewed every **15 seconds**. Standby instances poll every **20 seconds**, so the worst-case failover is **\~80 seconds**.

    When the new leader takes over, it resumes from the last persisted resume token in `_fw_checkpoints`. The guarantee is **at-least-once**: an event being processed at the moment of failover may be retried by the new leader, so your handler should remain idempotent for that window. Pair `SINGLE_LEADER` with [`@Checkpoint`](/guides/checkpoint-resume) to make failover seamless.
  </Accordion>

  <Accordion title="How many streams can a single instance handle? When should I scale horizontally?" icon="gauge-high">
    FlowWarden processes events **sequentially per stream** (one thread per `@ChangeStream` in imperative mode, `concatMap` per stream in reactive mode). Multiple streams run in parallel on independent threads — the limit per instance is your handler throughput and your JVM resources, not a hard cap from FlowWarden.

    If a single stream's sequential throughput becomes the bottleneck, the recommended pattern is to fan out to a message broker (Kafka, RabbitMQ) and parallelise on the consumer side. See [Threading & Scaling](/guides/threading-and-scaling) for the full pattern with code samples.
  </Accordion>

  <Accordion title="Is replaying from the DLQ idempotent? What if the event has already been processed?" icon="rotate">
    FlowWarden delivers events with **at-least-once** semantics, so the same event can reach your handler more than once — during retries, after failover, or when replaying from the DLQ. Handlers should always be idempotent (use the event's `_id`, the resume token, or a business key as a dedupe marker).

    The Core library is intentionally **write-only** for the DLQ — events accumulate in `_fw_dlq` with the original document, error, and stack trace. Reading and replaying DLQ entries is done from the Console. See [Retry & DLQ](/guides/retry-and-dlq) for retry policies, exception filtering, and the DLQ document schema.
  </Accordion>
</AccordionGroup>

***

## Alternatives & positioning

<AccordionGroup>
  <Accordion title="Why use FlowWarden rather than Apache Flink (with the MongoDB CDC connector)?" icon="diagram-project">
    Flink is a distributed stream-processing framework: distributed state, exactly-once semantics, windowing, joins, multi-source pipelines. It shines for **analytical pipelines** that aggregate or join multiple data sources with complex transformations — and it comes with a Flink cluster to operate.

    FlowWarden is a **lightweight library embedded in your Spring Boot application**, focused on reacting to MongoDB Change Streams (CQRS projections, cache invalidation, audit logs, event-driven notifications). No cluster to deploy, no distributed checkpointing infrastructure — checkpoint state lives in your own MongoDB.

    **Pick Flink** when you need a true stream-processing engine across heterogeneous sources. **Pick FlowWarden** when you stay within a MongoDB + Spring Boot world and want to react to changes without standing up dedicated streaming infrastructure.
  </Accordion>

  <Accordion title="What about Debezium / Kafka Connect?" icon="arrow-right-arrow-left">
    Debezium is a CDC connector that extracts MongoDB changes and publishes them as Kafka events. It decouples producers from consumers and lets you fan out to multiple downstream technologies through Kafka.

    FlowWarden consumes Change Streams **directly inside the Spring Boot application**, with no Kafka in the middle. Less moving parts, less infrastructure to operate — but tighter coupling to the Spring Boot consumer.

    **Pick Debezium** when you already have a Kafka backbone and need to feed multiple heterogeneous consumers (services in different languages, data lakes, analytics). **Pick FlowWarden** when you want to stay on a MongoDB + Spring Boot stack and avoid Kafka operational cost.

    <Note>
      You can also achieve a decoupled architecture **with** FlowWarden by isolating it in a dedicated Spring Boot microservice that consumes Change Streams and republishes events to Kafka, HTTP webhooks, or a queue (see [Threading & Scaling](/guides/threading-and-scaling) for the Kafka fan-out pattern). The trade-off then becomes: operate Kafka + Debezium, or operate a dedicated Spring Boot service.
    </Note>
  </Accordion>

  <Accordion title="How is this different from Spring Data MongoDB's native ChangeStream API?" icon="layer-group">
    The MongoDB Java driver and `ReactiveChangeStreamOperation` provide the low-level API for opening a Change Stream and receiving events. Everything else — discovery, lifecycle, resilience, observability — is on you.

    FlowWarden adds a production-ready layer on top:

    * Declarative annotations: `@ChangeStream`, `@OnInsert`/`@OnUpdate`/`@OnDelete`, `@Pipeline`, `@Filter`
    * Automatic resume token persistence via [`@Checkpoint`](/guides/checkpoint-resume)
    * Built-in retry policies and Dead Letter Queue ([`@RetryPolicy`](/reference/retry-policy), [`@DeadLetterQueue`](/reference/dead-letter-queue))
    * Multi-instance coordination with leader election (`SINGLE_LEADER` mode)
    * Startup-time validation of handler signatures and configuration
    * Console-side observability when paired with the Reporter

    **Pick the native driver** for a one-shot, highly specific use case where you want full low-level control. **Pick FlowWarden** as soon as you want a production-ready integration without re-implementing these cross-cutting concerns yourself.
  </Accordion>
</AccordionGroup>

***

## See Also

<CardGroup cols={2}>
  <Card title="Quickstart" icon="rocket" href="/quickstart">
    Get a working Change Stream handler in under 5 minutes
  </Card>

  <Card title="How it Works" icon="gears" href="/concepts/how-it-works">
    Startup lifecycle, event pipeline, and dual execution model
  </Card>

  <Card title="Deployment Modes" icon="server" href="/guides/deployment-modes">
    Full details on leader election and multi-instance coordination
  </Card>

  <Card title="Retry & DLQ" icon="rotate-right" href="/guides/retry-and-dlq">
    Exponential backoff, exception filtering, and DLQ schema
  </Card>
</CardGroup>
