Kafka Streams
Spring Boot
Data Streaming
Application Development
Java Programming

Kafka Streams with Spring Boot

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Kafka Streams and Spring Boot fit well together because Kafka Streams gives you the stream-processing model and Spring Boot gives you application wiring, configuration, and lifecycle management. The result is a normal Java service that can read from Kafka topics, transform records, maintain local state, and write results back out.

Set Up the Spring Boot Application

The usual starting point is Spring Boot plus Spring for Apache Kafka. You define Kafka bootstrap servers, a Streams application id, and any default SerDes settings in application configuration.

yaml
1spring:
2  kafka:
3    bootstrap-servers: localhost:9092
4    streams:
5      application-id: wordcount-app
6      properties:
7        default.key.serde: org.apache.kafka.common.serialization.Serdes$StringSerde
8        default.value.serde: org.apache.kafka.common.serialization.Serdes$StringSerde

The application-id matters because Kafka Streams uses it for internal topics, state directories, and consumer group coordination.

Define a Topology With StreamsBuilder

In Spring Boot, the most common style is to inject StreamsBuilder into a bean and describe the topology there.

java
1import org.apache.kafka.common.serialization.Serdes;
2import org.apache.kafka.streams.kstream.KGroupedStream;
3import org.apache.kafka.streams.kstream.KStream;
4import org.apache.kafka.streams.kstream.KTable;
5import org.springframework.context.annotation.Bean;
6import org.springframework.context.annotation.Configuration;
7
8import java.util.Arrays;
9
10@Configuration
11public class StreamTopology {
12
13    @Bean
14    public KStream<String, String> wordCountStream(org.apache.kafka.streams.StreamsBuilder builder) {
15        KStream<String, String> input = builder.stream("text-input");
16
17        KTable<String, Long> counts = input
18            .flatMapValues(value -> Arrays.asList(value.toLowerCase().split("\\W+")))
19            .filter((key, word) -> !word.isBlank())
20            .groupBy((key, word) -> word)
21            .count();
22
23        counts.toStream().to("word-count-output");
24        return input;
25    }
26}

This topology reads lines from one topic, splits them into words, groups by word, counts occurrences, and writes the counts to another topic.

Understand Stateless Versus Stateful Operations

Kafka Streams operations such as mapValues and filter are stateless. They transform each record independently.

Operations such as count, joins, windows, and aggregations are stateful. They need local state stores and changelog topics so the stream processor can recover after restarts.

That distinction matters when sizing the application. A stateless topology is simpler to scale and debug. A stateful topology is more powerful, but it needs disk, local state management, and careful testing of recovery behavior.

Let Spring Boot Own the Service Lifecycle

One reason Kafka Streams works well with Spring Boot is that it stays a normal application. Spring manages startup, dependency injection, config profiles, logging, and health wiring, while Kafka Streams runs the topology under the hood.

That makes it easier to add REST endpoints, metrics, or external service calls around the stream processor without building a separate runtime model.

For local development, it is also worth remembering that Kafka Streams creates state directories and internal topics behind the scenes. If your topology changes often during debugging, clear old local state carefully or use a new application id so stale state does not confuse your results.

Another operational benefit of Spring Boot is that you can layer ordinary actuator health checks, config profiles, and environment-based overrides on top of the stream processor. That keeps the streaming code inside the same application model the rest of your team already understands.

Common Pitfalls

  • Forgetting to set a stable application-id, which causes internal-topic churn and state confusion.
  • Relying on default SerDes when key or value types do not actually match the topic data.
  • Treating stateful operations as if they were cost-free stateless transforms.
  • Returning malformed records or blank tokens from split logic and then wondering why aggregates look wrong.
  • Mixing heavy blocking I/O directly into stream-processing steps and hurting throughput.

Summary

  • Spring Boot provides configuration and lifecycle support around a normal Kafka Streams application.
  • Use StreamsBuilder to define your topology as a Spring bean.
  • Stateless steps transform records directly, while stateful steps create local stores and recovery topics.
  • A good Kafka Streams service depends on correct SerDes, a stable application id, and careful handling of stateful operations.

Course illustration
Course illustration

All Rights Reserved.