| Kafka Streams 129 | ksqlDB | Apache Flink 129 | |
|---|---|---|---|
| Form | Java library in your app | SQL server | Cluster: JobManager, TaskManagers |
| Licence | Apache 2.0 | Confluent 17,245 Community License | Apache 2.0 |
| Sources | Kafka only | Kafka only | Kafka, files, CDC, databases |
| State | RocksDB plus changelog topics | Same, inside the server | Backends plus checkpoints |
| Event time | Stream time, grace periods | Same as Kafka Streams | Watermarks |
| Managed offers | None needed | Confluent Cloud 17,245 | Confluent Cloud, AWS 24 , Ververica, others |
Pick Kafka Streams when a JVM service owns its own state and should deploy like any other microservice, with nothing to operate beyond Kafka. Pick Flink for SQL-first teams, large state, many sources and sinks, or one engine for batch and streaming; it costs a cluster to run, or a managed service. ksqlDB remains convenient where Confluent Platform or Cloud already runs it, but its licence and status argue against starting new work on it. BookNest's genre totals fit Kafka Streams; its lakehouse landing (Streaming into the Lakehouse) and cross-source analytics fit Flink.
Moving from ksqlDB to Flink SQL is mostly mechanical: CREATE STREAM becomes CREATE TABLE with the kafka connector, CREATE TABLE ... AS SELECT becomes CREATE TABLE plus INSERT INTO (or a materialized table), and Avro 129 topics keep their registry through the avro-confluent format. Pull queries have no direct equivalent: serve them from the sink, for example a database or an upsert-kafka topic read into a cache.