What is the difference between subscribe() and assign() on a Kafka consumer, and when would you choose each?
answer
- subscribe = group + auto rebalance
- assign = manual, no group, no failover
- IllegalStateException if you mix them
- assign() can still commit offsets with group.id
- TopicPartition list for assign()
basics
~10 ssubscribe() joins a consumer group and lets Kafka assign partitions automatically (dynamic, rebalances on membership change). assign() manually pins specific partitions to the consumer with no group coordination or rebalancing.
solid answer
~40 ssubscribe(topics) opts the consumer into group management: it joins a consumer group, the group coordinator + a leader assign partitions across members, and partitions rebalance automatically when members join/leave. You get automatic fault tolerance and load balancing but no control over which partitions you own. assign(partitions) is self-managed: you hand the consumer an explicit list of TopicPartitions, it consumes exactly those with no group membership, no rebalances, and no automatic failover. Use subscribe() for elastic, fault-tolerant consumer groups (the common case). Use assign() when you need deterministic, static partition ownership — e.g. pinning partition N to instance N for stable parallelism, replaying specific partitions, or building your own assignment logic. You cannot mix the two on one consumer instance: calling both throws IllegalStateException.
go deeper
Know the one-line difference: subscribe = automatic/dynamic, assign = manual/static.
Explain group coordinator + rebalances for subscribe, and no failover for assign; know they're mutually exclusive.
Articulate concrete use cases for assign() (static parallelism, replay) and the offset-commit nuance.
Reason about when to abandon group management entirely for deterministic ownership and how to coordinate failover externally.
## The two subscription modes A Kafka topic is split into **partitions** — ordered, independently-consumable logs. A **consumer** reads records from one or more partitions. There are two completely different ways to decide *which* partitions a given consumer instance reads. ### subscribe() — group-managed (dynamic) ```java consumer.subscribe(List.of("orders")); ``` This enrolls the consumer in a **consumer group** (identified by `group.id`). Kafka then does the work for you: - The consumer finds the **group coordinator** (a broker) and sends a JoinGroup request. - One member becomes the **group leader** and computes a partition→member assignment using the configured `partition.assignment.strategy` (e.g. CooperativeStickyAssignor). - The assignment is distributed via SyncGroup. Each member is told which partitions it owns. - When a member joins, leaves, or dies (session timeout), a **rebalance** runs and partitions are redistributed. Benefits: automatic load balancing and failover. Cost: you don't control which partitions land where, and rebalances cause brief pauses. ### assign() — self-managed (static / manual) ```java consumer.assign(List.of(new TopicPartition("orders", 3))); ``` This bypasses group management entirely. You pass an explicit list of `TopicPartition` objects and the consumer reads exactly those. There is: - **No group membership** (no JoinGroup, no coordinator-driven assignment). - **No rebalancing** — the set never changes unless *you* call assign() again. - **No automatic failover** — if this instance dies, nobody takes over its partitions. Note: even with assign(), a `group.id` can still be set so the consumer can **commit offsets** to the `__consumer_offsets` topic — assign() opts out of *partition assignment*, not necessarily offset storage. ### Mutual exclusivity A single consumer instance is in exactly one mode for its lifetime of a call sequence. Calling `assign()` after `subscribe()` (or vice versa) without first calling `unsubscribe()`/clearing throws **`IllegalStateException`** ("Subscription to topics, partitions and pattern are mutually exclusive"). ### When to pick which - **subscribe():** the default. Elastic worker pools, scaling consumers up/down, needing fault tolerance. - **assign():** deterministic ownership — e.g. a stateful stream processor that pins partition i to pod i, replay/debug of one partition, or custom external coordination (e.g. via Kubernetes StatefulSet ordinals).
- Can a consumer using assign() still commit offsets to Kafka?Yes. assign() opts out of group-managed partition assignment, but if group.id is set the consumer can still commit to __consumer_offsets (manually or via auto-commit). It just won't participate in rebalances.
- What happens if you call both subscribe() and assign() on the same consumer?An IllegalStateException is thrown — topic subscription, pattern subscription, and manual assignment are mutually exclusive on a single consumer instance.
saying these in an interview costs you the question
- Saying assign() automatically fails over to another instance — it does not.
- Claiming assign() triggers rebalances — it never does.
- Saying you can call subscribe() and assign() together to mix modes.
- Thinking assign() means you cannot commit offsets at all.