Running Kafka Streams applications in production

Running Kafka Streams in production means planning instance and thread counts, standby replicas, rack-aware assignment, exactly-once settings, internal topics and monitoring before traffic arrives. This page explains the decisions and what a planned rollout involves.

On this page

Running Kafka Streams applications in production: what your team must decide first

A team with a working Streams prototype should decide four things before it runs as a service: the Kafka version and its upgrade path, the number and size of application instances, how state is stored and recovered, and who owns the internal topics the application creates. Kafka Streams is a client library, not a separate cluster, so each application instance is a Java process that joins a consumer group, reads input topics, keeps local state and writes results back to Kafka. The cluster supplies three things the application depends on: the input and output topics, the changelog topics that back each local state store, and the consumer group coordination that assigns partitions to instances. A prototype on a single laptop hides all three. A production setup needs them planned as infrastructure, because a failed instance, a rebalance or a restart all move work and state around.

Kafka Streams runs on Java 11 or later for client applications, according to the Kafka upgrade notes, and the broker version you choose sets which Streams features and protocols are available. Check the supported releases on the Apache Kafka downloads page and align your cluster, client libraries and Streams dependency with one tested version set. Confirm with your platform team how brokers will be upgraded while applications are running, since rolling upgrades are supported only from recent releases to the latest version. Plan production sizing and recovery only after these versions are fixed, because they determine the behavior of standby replicas, rebalancing and exactly-once processing covered in the sections that follow.

The practical test is whether your team can answer, in writing, what happens when one instance dies during a rebalance, which topics the application creates and who may delete them, and how it will reset the application to reprocess input. If those answers are not yet clear, the prototype is not ready to become a service, and the work to close those gaps is the planning step that a production design should start with. Ask any implementation partner to write these decisions into the scope before build work begins, so that sizing, recovery and monitoring are tested against your own topics and volumes rather than assumed.

How to size Streams instances and threads

In Kafka Streams, the input partition count sets the ceiling on parallel tasks, and the thread and instance counts decide how those tasks are spread across machines. The right layout depends on partition counts, state size and throughput together, so the cards below are the checks to run before choosing numbers.

Partition count caps parallelism

Each input topic partition maps to one task, and a task is processed by one thread at a time. If a sub-topology reads from 12 partitions, it can never use more than 12 active tasks, so extra threads or instances beyond that count sit idle. Check the partition count of every source topic the application reads, including repartition topics it creates itself, because the smallest count in a sub-topology sets the limit. Changing partition counts later affects key distribution and state placement, so decide them with the application in mind.

Threads per instance

The num.stream.threads setting controls how many stream threads run inside one application instance, and each thread takes a share of the tasks assigned to that instance. More threads help when one machine has spare CPU and tasks are waiting, but each thread adds its own consumer, producer and state store handles. Size the thread count against the cores and memory available to the process, then load test to confirm that tasks are not queuing behind a single slow thread.

Instance count and task distribution

Instances in the same application share the work by splitting the tasks across them, so total parallel capacity is roughly the number of instances multiplied by the threads per instance, bounded by the partition count. Adding instances increases capacity for compute-heavy processing, but each new instance triggers a rebalance that pauses some processing. Plan for the number of instances needed at peak, plus enough headroom that losing one instance does not leave the remaining ones overloaded.

State size per task

Stateful operators such as aggregations and joins keep local state stores, and each active task owns its share of that state on local disk. The state held per task determines how much disk and memory each instance needs and how long a task takes to restore after it moves. Measure state size in a staging run with production-like key cardinality, and confirm that the instances you plan can hold their assigned tasks' state on local volumes with room for compaction and restore.

Which Streams settings fit which production goal

This table compares five Kafka Streams settings by the production goal each one serves, the trade-off it brings, and what to confirm in the Kafka 4.3 documentation before you set it. Read each row against the failure or constraint you are trying to reduce, then check the exact property names and defaults for your release.

SettingWhen it fitsTrade-offConfirm before setting
num.standby.replicasStateful apps where restoring large state stores after a failover or rebalance would keep a partition's results unavailable for too longEach standby copy consumes extra disk, memory and network for changelog replay, and the cost scales with the number of stateful tasksConfirm the default value, how standbys are placed relative to active tasks, and whether your state size makes standbys worth the overhead
rack.aware.assignment.tagsClusters spread across racks or availability zones where losing one zone should not take out both an active task and its standbyPlacement becomes more constrained, so assignment may be less balanced and rebalances can take longer to settleConfirm the tag syntax, how it interacts with standby replicas, and the matching broker and client rack configuration in the 4.3 documentation
processing.guarantee = exactly_once_v2Read-process-write pipelines that write back to Kafka and cannot tolerate duplicate outputs after retries or zombie instancesTransactions add latency and broker load, and the guarantee covers Kafka-to-Kafka flows only, not writes to external databasesConfirm the broker version and client version requirements, and check whether your Kafka 4.3 release still lists this value as the recommended setting
replication.factor (internal topics)Production clusters where changelog and repartition topics must survive a broker loss without data gapsHigher values multiply storage and write traffic for every internal topic the application createsConfirm the Streams setting name for internal topic replication, the default, and whether it should match your broker default replication factor
Server-side rebalance protocol (KIP-1071)Large consumer groups where client-side rebalance coordination causes long pauses and you run brokers that support the new protocolRequires broker and application versions that support it, and tooling and monitoring change, so existing runbooks may need updatesConfirm the Kafka 4.2 production readiness notes, how to enable the protocol, and compatibility with your broker and application versions before a rollout

Standby replicas and rack-aware assignment for faster recovery

Standby replicas keep a warm copy of a stateful task's state store on another instance, so when the active task's instance fails, Kafka Streams can promote the standby instead of rebuilding state from the changelog topic from the beginning. The setting is num.standby.replicas, which defaults to 0. Each standby is a full copy of the state for that task, so you pay for it in disk on every standby instance, in network traffic as the standby tails the changelog, and in extra restore work on each rebalance. Size the disk for the largest task's store on each instance, not for the average, and confirm the default and the behavior of standby assignment for your Kafka Streams version in the Kafka documentation before you set a value.

Rack-aware assignment tells the Streams assignor to place an active task and its standbys on instances in different failure domains, such as availability zones or racks. Without it, a standby can land on the same host or zone as its active task, and a single zone outage removes both copies at once. The assignor uses the rack.id value each instance advertises, and you set it through the client configuration of every instance in the application. Plan the rack labels with your infrastructure team before deployment, because a mismatched or missing label quietly weakens the placement you expect.

Expect standby placement to add work during rebalances. The assignor must move standby copies as instances join, leave or restart, and each move means a restore from the changelog, which competes with processing for I/O and network. Test a rolling restart and a single-instance failure in a staging environment with production-like state sizes, and measure how long the standby takes to catch up. Confirm how standby lag and restore progress are exposed for your version through the Streams metrics, and set alerts before you rely on standbys to meet a recovery target.

How a Kafka Streams service moves from test to production

This sequence turns a tested Kafka Streams application into a production service in which each setting is chosen on purpose and each stage has a check that confirms it before the next one starts.

  1. Confirm Kafka, client and Java versions

    The platform team confirms the broker version, the Kafka Streams library version and the Java runtime on every instance. Kafka 4.x brokers need Java 17, while clients and Kafka Streams applications need at least Java 11, according to the upgrade notes. Check that the Kafka Streams client version is one the brokers support, and that it matches the version you tested. Confirm the broker release against the downloads page, because only the listed supported releases receive bugfixes. Done means a written version matrix signed off by the platform owner and the application owner, with the test environment built from the same versions.

  2. Plan partitions and internal topics

    The application team maps each input and output topic to a partition count, because Kafka Streams tasks follow input partitions and that count caps how many threads can work in parallel. Confirm that co-partitioned inputs share a partition count and key scheme before joins are deployed. List the internal changelog and repartition topics the application creates, then decide who owns their names, retention and replication. Check the plan by running the topology in a test cluster and comparing the created topics with the written list. Done means an approved topic inventory that the broker administrators can apply, and a diff between that inventory and the topics the application actually created shows no surprises.

  3. Set replication and exactly-once settings

    The platform team sets the replication factor for the application's internal topics and the producer and transaction settings the application will run with. Choose the processing guarantee deliberately: exactly_once_v2 is the setting to confirm for brokers and clients that support it, and the team should verify this against the Kafka Streams documentation for the release in use. Set min.insync.replicas so that a single broker failure does not stop writes. Record each value in configuration under version control. Check the result by reading the effective configuration from a running test instance and comparing it with the written values. Done means every guarantee setting is traceable to a review decision.

  4. Configure state directories on persistent storage

    The platform team places state.dir on storage that survives pod or host restarts, sized for the state stores the topology will hold. Local RocksDB state is restored from changelog topics when it is missing, so disk loss turns into a restore workload. Confirm that each instance has its own directory, that the directory is writable by the service account, and that disk capacity is monitored with an alert before it fills. Ask the storage team to confirm the volume class and snapshot policy in writing. Check by restarting one test instance and verifying that it reuses local state instead of rebuilding it. Done means the state directory is persistent, isolated per instance and covered by a documented restart test.

  5. Deploy instances and standby replicas

    The platform team rolls out the application in small groups of instances. Set num.standby.replicas to a value agreed in the review, which keeps warm copies of state for faster failover at the cost of extra disk and network use. Where the cluster spans racks or zones, configure rack-aware assignment so standby copies land in different failure domains. Confirm that each instance has a distinct application.id and client.id pattern for dashboards. Check that the group reaches a stable assignment with every task owned by exactly one instance. Done means all instances are running, the assignment is stable, and the standby placement matches the failure domains you chose.

  6. Verify lag, rebalances and restore behavior

    The operations team watches consumer lag on the input topics, the rebalance rate and the restore progress of state stores while instances start and while one instance is deliberately stopped. Lag should return to a steady level after the initial catch-up, and rebalances should settle without repeated cycles. Run a controlled restart and confirm that the replacement instance restores state within the window the team agreed in advance. Check the Kafka Streams metrics exposed by the application and wire them into alerts for lag, rebalance and restore time. Done means a recorded test run showing steady lag, a bounded rebalance and a successful restore, with alerts in place before production traffic is switched on.

  7. Confirm the runbook before cutover

    The application and operations teams write a short runbook covering how to reset the application, how to add or remove instances, what to do after a failed restore and who approves each action. Confirm that resetting the application is possible in the test environment and that its effect on output topics is understood. Record the owner for each internal topic and each alert. Check by walking through the runbook with someone who did not write it. Done means the runbook is reviewed, the reset procedure has been rehearsed in test, and the on-call team can name the first action for each alert.

What exactly_once_v2 guarantees and what it does not cover

exactly_once_v2 makes the records a Streams application writes to Kafka topics appear once, but only inside Kafka. Streams wraps each task's processing in a Kafka transaction, so output records and the consumer offset commits for the input they came from are committed together or not at all. Consumers reading with isolation.level set to read_committed then skip aborted output after a failure. The guarantee covers the read-process-write loop between Kafka topics. It does not cover side effects. If a processor updates a relational database, calls an HTTP API or sends an email, a retry after a crash can repeat that action, because the external system is outside the transaction.

Before you enable the setting, check that every broker in the cluster and every Streams application runs versions that support it, and confirm the exact requirement for your release in the Kafka upgrade notes. Mixed versions during a rolling upgrade are where teams most often find that a feature they assumed was on is not active. Also confirm the processing.guarantee value your application actually runs with, because a configuration typo or an override in a deployment template can silently leave the application at at-least-once.

Test the boundary rather than trusting the setting. A failure drill can be simple: run the application against a test cluster with a steady input feed, kill instances at random points during processing (including during a commit), restart them, and then compare output counts and keys against the input. Repeat the same drill with a sink that writes to a database and you will see what exactly_once_v2 does not protect. Where the external write must be idempotent, plan for it explicitly, for example with upserts keyed on a business identifier. Agree on the drill's pass criteria and the owner of the external sink before the first production release.

Which metrics and tooling show a Streams service is healthy

Which Kafka Streams metrics should I alert on first?

Start with consumer group lag on the input topics, the rebalance rate of the application, and the state of its tasks, because these three signals show most failures before users notice them. Add processing latency and the error or skipped-record counts once those baselines are known. Set thresholds from your own traffic pattern in a test environment rather than copying values from another system. Check the metric names and tags against the Kafka Streams documentation for your exact version, since metric groups have changed across releases. Route alerts to the team that owns the application so that a lag spike leads to a named responder.

How do I spot a stuck Kafka Streams task?

A stuck task shows up as a partition whose committed offset stops advancing while its end offset keeps growing, and the owning thread's processing rate drops to zero. Compare the task's position with the log end offset for each partition the instance owns. If the task keeps moving between instances, the cause is usually a rebalance loop rather than slow processing, so check the rebalance rate first. Thread state that stays in a restoring or partitions-revoked state for a long period also points to a problem. Capture thread dumps and the application logs at the same moment so you can tell a blocked processor from a slow external call.

How do I read restore time after a Streams instance restarts?

Restore time is the interval during which a task replays its changelog topic into the local state store before it can process new records. Read it from the restore metrics for each store, together with the number of records restored and the changelog lag. Long restores usually come from large changelogs, frequent compaction gaps, or state stored on slow disks. Standby replicas shorten restores because a warm copy of the state already exists on another instance, which is why their effect should be measured in your environment. Record a baseline restore time before and after each change so the result is evidence rather than an impression.

Which RocksDB metrics matter for a Streams state store?

The useful signals are write stalls, memtable and block cache hit behavior, compaction pending bytes, and the number of open files, along with the store's own size on disk. Rising stall counts or growing pending compaction bytes indicate that the disk or the memory budget cannot keep up with the write rate. Growing store size with flat record counts can signal that retention or cleanup settings do not match the workload. Expose these metrics through the JMX or metrics reporter you already run, and tie them to the same dashboard as lag so that a disk problem and a lag problem can be read together. Confirm metric names with the version of Kafka Streams you deploy.

What does the kafka-streams-groups tool show?

The kafka-streams-groups.sh tool describes Streams groups and their members, which makes it useful for checking assignments and lag from the command line during an incident. It helps confirm which instance owns which partitions and whether any member is missing. Run it against the bootstrap servers with the same client configuration your application uses, including the security settings, so that access control does not hide the group. Scripts and output format can differ between Kafka releases, so verify the options with the help output of your installed version before writing runbooks around them. Keep a saved snapshot from a healthy period to compare against during an incident.

How do I tell whether rebalances are hurting a Streams service?

Frequent rebalances stop processing across the affected partitions, so a rising rebalance rate is one of the most important signals to track. Compare rebalance counts with deployments, scaling events, and network or pod restarts to find the trigger. Long session timeouts or slow processing inside the poll loop can make a healthy instance look dead, which causes repeated reassignment. If your group uses the server-side rebalance protocol, check the protocol-specific metrics for your Kafka version. Review the timing settings with your platform team, because changes to them alter failure detection as well as rebalance frequency.

Which errors and latency signals show a Streams service is unhealthy?

Track processing latency per task or per processor node, the rate of records failing deserialization, and the number of records dropped or skipped by the error handlers you configure. Most applications should not skip silently, so confirm which handler your code uses and whether skipped records are logged or sent to a dead letter destination. Latency that grows while lag stays flat often points to a slow downstream dependency, such as a database write inside a processor. Errors that appear after a deployment usually reflect a serialization or schema change. Pair these counters with the application logs so each alert links to a specific record type or processor.

Can my team run this monitoring itself, and what would a partner add?

Your own team can run this monitoring if it already operates a metrics stack, can export Kafka and Streams metrics, and has an owner for alert tuning. The work is mostly configuration: exposing metrics, building dashboards, writing alert rules, and documenting runbooks for lag, rebalance, and restore events. A partner engagement is usually scoped in writing as a fixed set of dashboards, alerts, and runbooks for named applications, with the deliverables and timeline agreed before work starts. Ask any provider to list the metrics, thresholds, and evidence they will hand over, and to state who maintains the alerts after handover. Ongoing tuning and testing are available as retainers when the team wants them.

Managing internal topics and resetting an application

Kafka Streams creates topics on your behalf, and those topics hold the state and progress your application depends on. The cards below cover who creates them, how long they live, how to reset an application safely, and which checks to complete before any reset touches live data.

Changelog topics back state stores

Each state store that is backed by a changelog gets a compacted topic that records every update, so a replacement instance can rebuild local state after a failure or rebalance. The application creates these topics, usually named with the application ID as a prefix, and their size grows with the number of distinct keys rather than the number of messages. Check the partition count and replication factor the application requests, and confirm that brokers allow the application to create topics with those settings.

Repartition topics follow key changes

When a stream operation changes keys, such as a grouping by a new key, Kafka Streams writes intermediate records to a repartition topic so that each key lands on the correct task. These topics hold data only until downstream processing commits, but their retention still determines how far back a restart can replay. Ask your platform team which retention setting applies to these topics and whether a broker-side default overrides the application's intent.

Ownership of internal topics

The application that creates internal topics owns their lifecycle, but your platform team usually owns the cluster policy that governs them. In many organizations, a creation policy or a restricted topic-creation ACL blocks the application from creating them at startup, and the deployment then fails in a way that looks like an application bug. Agree in writing who creates internal topics, who changes their settings, and whether they are created by the application or provisioned ahead of time.

ACLs for internal topics

Internal topics need read and write access for the application principal, and a reset also needs delete access on the topics it removes. Grant access by prefix only to the principal that runs the application, and keep those permissions separate from operators who can run the reset tool. Confirm the authorizer rules in the cluster, because a resource without an ACL is restricted to super users unless the allow-everyone setting is enabled.

The application reset tool

The kafka-streams-application-reset tool moves committed offsets of the application's input topics back to a chosen point and deletes the internal topics so processing restarts cleanly. It must run while no instances of the application are active, and it does not reset external systems that the application wrote to. Record the application ID, the target offsets, and the topics involved before running it, and keep the application stopped until the reset completes.

Rehearse resets before production

A reset on live data reprocesses records that downstream systems may already have received, which can produce duplicates or double-counted results. Rehearse the full sequence on a copy of the topics in a non-production cluster, time how long reprocessing takes, and write the rollback steps down. Schedule production resets for a window agreed with the teams that consume the outputs, and confirm that the reset plan is part of your change process.

What a production Kafka Streams rollout costs and needs from your team

What drives the cost of a production Kafka Streams rollout?

The cost follows the written scope: how many Streams applications are in play, how much state each one keeps, how many environments and failure scenarios must be tested, and how much compliance evidence the work must produce. Each application adds design, configuration, testing and runbook work, and stateful applications add restore and disk sizing work on top. Cluster ownership matters too, because a rollout on a cluster you already run costs less to integrate than one that also needs broker changes. Ask the quote to list each application separately with its state profile and environments.

How long does a Kafka Streams production rollout take?

Duration depends on scope rather than on a fixed template. A single stateless application with an existing cluster is a much smaller piece of work than several stateful applications that need standby replicas, rack-aware assignment, load testing and monitoring built in. Fixed-scope engagements agree timelines in writing before work starts, so the timeline should appear in the statement of work with its dependencies listed, such as access to test clusters, change approvals and the release window for your upgrade path. Ask for milestones per application rather than a single end date.

What does the work need from our engineers and infrastructure?

The work needs named people who know the business logic of each Streams application, people who run the Kafka cluster, and someone who owns the platform the applications run on, whether that is virtual machines or Kubernetes. Your infrastructure must provide persistent volumes for state stores, enough broker capacity for changelog and repartition topics, and a test environment that resembles production. Confirm access to these systems early, along with the Java runtime your organization approves. Kafka Streams applications require at least Java 11, and brokers on 4.x require Java 17, so the runtime version affects what can be deployed.

Can an internal team run a Kafka Streams rollout alone?

An internal team can do it alone if it already operates Kafka brokers, has Java developers who have built stateful stream processing, and has time to test failure scenarios such as instance loss, rebalances and state restoration. Teams without that experience usually find the hard parts are operational rather than coding: sizing threads and instances, setting up standby replicas, and deciding how to reset an application safely. A partner can cover part of this, such as design review, test harness work or runbooks, while your team keeps ownership. Decide which parts you want to own before requesting a quote.

Which costs are one-time and which recur?

One-time costs include design, application configuration, load and failure testing, monitoring setup and the initial runbook. Recurring costs include running the applications, monitoring and alert tuning, Kafka version upgrades, dependency updates, and rerunning tests after changes to topology or traffic. Retainers for ongoing support, upgrades and continuous testing are available from DeployOpen and are priced from the written scope. The quote should separate these categories so you can budget the run phase, and it should state what happens when the Kafka cluster or the Streams library changes version.

What compliance evidence should a Kafka Streams rollout produce?

A rollout can produce the technical evidence that auditors and assessors typically ask for, such as documented configuration, access control settings, change records, test results and monitoring definitions. DeployOpen prepares systems, controls and evidence for compliance assessments, but it does not issue audit reports, attestations or certifications, and independent auditors make that determination. Ask the quote to name which control areas the evidence covers and in what format. Also confirm which regulations apply to the data flowing through the applications, because that decides how much evidence you need.

What should a written quote for this work include?

A useful written quote lists each Streams application with its input and output topics, state store profile, environments, and integrations. It should state the deliverables, such as configuration, tests, dashboards, alert rules and runbooks, and the acceptance criteria for each. It should name the Kafka and Java versions in scope, the upgrade assumptions, and the client responsibilities. Ask for the exclusions in writing, including anything about the Kafka cluster itself, so you know which work sits outside the agreed scope. Most engagements are fixed-scope, so the quote and the scope document should match.

How DeployOpen scopes and supports Streams services

DeployOpen plans, implements, hardens, documents and supports self-hosted open-source platforms inside the client's own infrastructure, including the Kafka clusters that Kafka Streams applications depend on. DeployOpen is a Chainscore Labs company. For a Streams service, that work can cover the instance layout, the Kafka cluster settings the application relies on, the internal topic and state store plan, monitoring, and the runbooks for resetting an application. The client keeps the cloud accounts, data centers or air-gapped networks where everything runs, so the application data and credentials stay under the client's control.

Most engagements are fixed-scope. Before work starts, the written scope names the Streams applications, the Kafka version and deployment target, the processing guarantee each application needs, the monitoring stack, the handover material and the acceptance checks. Timelines follow from that scope and are agreed in writing. DeployOpen does not publish a price list, so a quote follows from the written scope. To get a comparable quote from any partner, ask for the list of applications and topologies covered, which environments are in scope, who performs load and failure testing, and which items are one-time versus recurring.

Ongoing support, Kafka version upgrades and continuous checks are available as retainers. For Streams services, a retainer usually matters most around upgrades, because the application's client library, the broker version and any rebalance protocol choice must move together. Confirm with the partner which upgrade paths they cover, how they handle a state store reset during an incident, and how quickly they respond to production issues. Those terms belong in the written agreement, not in a general service description.

Talk to our team.

Tell us what you're working on, whether it's a deployment, an audit, a security test or a cyber range. You'll speak with an engineer who can help you scope it.

  • 30-minute call: free, with no obligation.
  • NDA on request: we can sign before you share details.
  • Clear next steps: a scope and plan after the call.