Skip to content
Stribog

Streaming

All writing

NATS vs Kafka: Strimzi and Redpanda Off Confluent Cloud

A production ops playbook for a self-owned event backbone: Strimzi's Kafka lifecycle on Kubernetes, Redpanda's single binary, and NATS — off Confluent Cloud.

Stribog13 min readUpdated 6 Aug 2026

The event backbone is the most load-bearing piece of infrastructure most organisations never chose to own. It starts as one Kafka topic behind a feature, and within two years it is the nervous system — every service publishes to it, every analytics job reads from it, and an outage of it is an outage of everything. That is precisely the layer teams most often rent from Confluent Cloud, and where renting compounds into the deepest lock-in: not because Kafka is proprietary, but because the operational muscle has been outsourced, egress is metered, and the wire your estate speaks now sits on someone else's balance sheet.

This article is the production ops playbook for taking that layer back — not as a cost-cutting stunt, but as an engineering decision with its eyes open. It covers three tools that together span the whole design space: Strimzi, which turns Apache Kafka into declarative Kubernetes objects; Redpanda, the single-binary, Kafka-compatible engine for teams that want the protocol without the JVM; and NATS JetStream, for the large class of workloads that never needed Kafka at all. It also covers the part most migration pitches skip: the honest cost model, the day-2 work that does not disappear when you leave the managed service, and the gate that tells you when staying on Confluent is still the right call.

The Confluent Cloud meter, and what it actually costs

Confluent Cloud's serverless tiers price four dimensions: eCKU-hours, data ingested, data egressed, and data retained. On the Basic tier the published rates are $0.05 per GB in, $0.05 per GB out, and $0.08 per GB-month retained, plus $0.14 per eCKU-hour after the first free eCKU — before regional multipliers on throughput, and before the three-times replication factor that durable storage billing applies to retained data. Those numbers look small until you multiply them by a real firehose with real fan-out. In one independent breakdown of a 300 MiB/s workload, egress alone reached tens of thousands of dollars a month and became the single largest line item on the bill — because every consumer group, every mirror, every analytics reader pays the meter again on the same bytes.

The infrastructure gap is real and it widens with scale. AxonOps' 2026 cost analysis put a modest 3-broker, 45 MB/s cluster at roughly $571/month self-hosted against $1,216/month on Confluent Cloud — a meaningful but survivable difference. At 30 brokers and 1.875 GB/s the same analysis put self-hosting near $8,820/month against a Confluent Cloud range of $42,093–$53,773/month. That is not a rounding error; it is the difference between a line item and a headcount, and it is the same repatriation calculus that governs any serious cloud exit — the premium is structural at scale, not marginal.

So the decision is not "managed is a rip-off." It is narrower and more useful: at what scale, and with what team, does owning the backbone become the disciplined choice rather than the reckless one? The rest of this article answers that by tool — because the right answer for a 200-topic Kafka estate with Connect and Streams is not the right answer for a fleet of edge services trading small messages.

Strimzi: Kafka broker lifecycle as declarative objects

Strimzi is the reason self-managed Kafka on Kubernetes stopped being a synonym for pain. It is a CNCF Incubating project (accepted 2019, incubating since 2024) whose operator models an entire Kafka cluster as custom resources: a Kafka for the cluster, KafkaNodePool resources for broker and controller groups, and KafkaTopic / KafkaUser for topics and principals. You declare intent — brokers, storage class, listeners, TLS-authenticated clients — and the operator's reconciliation loop drives the cluster to that state through node failures and rolling upgrades. It is GitOps-native: desired state lives in a repository, reviewed like any other code.

The single most important recent change is the removal of ZooKeeper. Strimzi removed ZooKeeper support in 0.46.0, leaving KRaft — Kafka's own Raft-based consensus — as the only metadata mode; its later 1.0 release then dropped the older CRD API versions and left v1 as the only served API. In practice this halves the number of distributed systems you operate: there is no separate ZooKeeper ensemble to size, secure, back up, and reason about during an incident. A KRaft controller quorum lives inside the Kafka cluster itself, and Strimzi models it as a dedicated node pool. Fewer moving parts is not a cosmetic win — it is one fewer consensus system in your audit scope and one fewer thing to page on at 3 a.m.

yaml
# KRaft controller quorum — replaces the old ZooKeeper ensemble entirely.
apiVersion: kafka.strimzi.io/v1
kind: KafkaNodePool
metadata:
  name: controllers
  namespace: events
  labels: { strimzi.io/cluster: backbone }
spec:
  replicas: 3
  roles: [controller]           # dedicated KRaft metadata quorum
  storage:
    type: persistent-claim
    size: 20Gi
    class: local-nvme
---
apiVersion: kafka.strimzi.io/v1
kind: KafkaNodePool
metadata:
  name: brokers
  namespace: events
  labels: { strimzi.io/cluster: backbone }
spec:
  replicas: 3
  roles: [broker]
  storage:
    type: persistent-claim
    size: 1Ti
    class: local-nvme
    deleteClaim: false          # keep the data if the pool is deleted
---
apiVersion: kafka.strimzi.io/v1
kind: Kafka
metadata:
  name: backbone
  namespace: events
spec:
  kafka:
    version: 4.2.0
    listeners:
      - name: tls
        port: 9093
        type: internal
        tls: true
        authentication: { type: tls }   # mutual TLS: only authenticated clients
    config:
      default.replication.factor: 3
      min.insync.replicas: 2            # acks=all needs 2 in-sync replicas to commit
      offsets.topic.replication.factor: 3
    authorization: { type: simple }     # topic/group ACLs enforced by the broker
  entityOperator:
    topicOperator: {}                   # KafkaTopic CRs become real topics
    userOperator: {}                    # KafkaUser CRs mint TLS certs + ACLs
A production-shaped Strimzi cluster: a dedicated KRaft controller pool, a broker pool on local NVMe, mutual-TLS listeners, and min.insync.replicas=2 so an acks=all produce is not acknowledged until two replicas hold it. The Topic and User operators turn ACLs and topic definitions into reviewable Git objects.

Two settings in that manifest carry the whole durability story. min.insync.replicas: 2 with a replication factor of 3 means a producer using acks=all is never told its write succeeded until at least two brokers have it — the streaming equivalent of quorum-synchronous commit, and the difference between "we failed over" and "we failed over and lost four seconds of orders." The mutual-TLS listener and simple authorization mean the brokers speak only to clients holding a certificate the User Operator minted, with ACLs enforced per topic and consumer group. That is audit-grade access control as Kubernetes objects, not a console click-through. Broker metrics land in the same observability stack you already run, so lag and under-replicated partitions sit next to everything else.

Strimzi turns a Kafka cluster into declarative Kubernetes objects: a KRaft controller quorum and a broker node pool reconciled by the Cluster Operator, with cold segments tiered to an object store you own. No ZooKeeper, no managed control plane between you and the log.

The one architectural decision Strimzi does not make for you is where the bytes ultimately rest. Kafka's tiered-storage support lets brokers keep only hot segments on local NVMe and offload cold segments to object storage — which means the retention window that would blow up your local disk instead lands in an S3-compatible store you own. That object store is the sovereignty boundary: your history lives where you decide, under your keys, with no provider able to meter reads against it. It is the same pattern that makes the stateful data layer sovereign — the compute is cattle; the durable state sits in a boundary you control.

Redpanda: the single-binary bet

Strimzi runs Apache Kafka, the JVM and all. Redpanda takes the opposite bet: reimplement the Kafka wire protocol in C++ so that any existing Kafka client, tool, or connector works unmodified, but the engine underneath is a single binary with no ZooKeeper, no JVM, and no external dependencies. Internally it uses a thread-per-core architecture on the Seastar framework and Raft consensus per partition, which eliminates the JVM garbage-collection pauses and lock contention that make Kafka's tail latencies unpredictable. The practical effect is that a broker comes up quickly (controller snapshots keep cold start fast compared with long JVM log-recovery paths), uses far less memory, and ships a schema registry and HTTP proxy inside the same process.

The reason this matters for a sovereignty practice is operational surface, not benchmarks. A single binary is easier to own end to end: one artifact to build, sign and attest in your supply chain, patch, and reason about when it misbehaves. For a team taking on a self-managed backbone for the first time — especially without deep JVM-tuning experience — fewer moving parts is worth more than a latency percentile. You trade the vast Kafka ecosystem's maturity for a thinner, more legible system, and for many mid-scale estates that is the right trade.

Because Strimzi-run Kafka, Redpanda, and Confluent all implement the same Produce/Fetch/Metadata protocol and consumer-group coordination, producers and consumers do not care which they talk to. That is a real exit ramp: stand up Redpanda beside Confluent, mirror topics, cut bootstrap servers over, decommission the old cluster — no application rewrite. Remaining lock-in lives above the protocol (managed connectors, ksqlDB, Stream Governance); stay on the open wire and keep vendor-only surface thin.

NATS JetStream: when you never needed Kafka

A large fraction of what gets built on Kafka is not a durable, replayable, partitioned commit log at all — it is service-to-service messaging that acquired Kafka because Kafka was already there. For that workload, NATS is a different and often better shape. Core NATS is a tiny, high-performance pub/sub and request-reply system; JetStream adds persistence on top — replicated, file-backed streams with at-least-once and exactly-once delivery, consumer acknowledgement, and retention policies — without the operational weight of a Kafka cluster. The whole server is a single small Go binary, trivial to run at the edge or embed alongside services, with subject-based addressing instead of Kafka's partition model.

The cost argument here is sharp because the comparison is against a managed service with no self-hosted option. Synadia — the company that maintains NATS — published a benchmark putting NATS 59–87% below Amazon Kinesis on cost depending on message size and scale, with a 3-node NATS cluster on c5n.xlarge instances across three availability zones costing about $473/month in compute, and single-digit-millisecond delivery latency against Kinesis's hundreds of milliseconds. Treat the exact percentages as a vendor benchmark and measure your own workload — but the structural point holds: NATS's default consumer model already does what Kinesis charges a premium (Enhanced Fan-Out) to provide. When your requirement is many low-latency consumers of the same subject, that is a fundamental architectural advantage, not a tuning delta.

shell
# A JetStream stream is a replicated, file-backed log — no Kafka, no JVM.
# Three replicas, a 7-day retention window, discard oldest when full.
nats stream add ORDERS \
  --subjects "orders.>" \
  --storage file \
  --replicas 3 \
  --retention limits \
  --max-age 168h \
  --discard old \
  --defaults

# A durable, explicitly-acknowledged pull consumer — at-least-once by default.
nats consumer add ORDERS fulfilment \
  --pull \
  --ack explicit \
  --deliver all \
  --max-deliver 5 \
  --filter "orders.created" \
  --defaults
Standing up a durable NATS JetStream stream and a consumer is two CLI calls — or, in production, two lines of a declarative account configuration reconciled from Git. No brokers to size, no partitions to plan; subjects and replicas are the whole model.

NATS is not a Kafka replacement and pretending it is will burn you. It has no equivalent of Kafka Connect's connector ecosystem, its stream-processing story is thinner, and very high-throughput analytical fan-out is Kafka's home turf. The discipline is to match the tool to the workload: use NATS for the messaging, eventing, and control-plane traffic that never justified a Kafka cluster, and keep Kafka (via Strimzi or Redpanda) for the durable, high-throughput, replayable log that feeds analytics. Many sovereign estates end up running both — NATS as the lightweight nervous system, Kafka as the system of record — and that is a coherent architecture, not a failure to standardise. The same backbone also doubles as infrastructure for other systems: wasmCloud schedules its components onto a lattice over a NATS control plane, so a NATS deployment already earned for messaging lowers the marginal cost of adopting it.

Choosing the backbone: a decision framework

The three tools are not competitors so much as answers to three different questions, and a single decision path routes you cleanly. The first gate is the one every honest self-hosting argument has to lead with, and it is not technical.

Gate one — is there a team to own day-2? Running a streaming backbone means owning topic and subject design, ACL and account governance, consumer-lag monitoring, connector and schema evolution, capacity planning, and incident response. If no one will own that, the managed service is the correct answer today and the work is to build the capability before you migrate — exactly as it is for any repatriation. Gate two — do you need the Kafka wire protocol and a durable, replayable, partitioned log? If yes, you are choosing between Strimzi and Redpanda. If no — if you need messaging, not a log — NATS is lighter and cheaper. Gate three — do you need the full Kafka ecosystem (Connect, Streams, mirroring, hundreds of topics)? If yes, Strimzi's Apache Kafka is the safe choice; if you want the protocol with minimal ops, Redpanda's single binary wins.

One decision path, three sovereign outcomes. The first gate is organisational, not technical: without a team to own day-2 operations, managed still wins. Past it, the log-versus-messaging split routes you to Strimzi, Redpanda, or NATS — each a system you run and can exit.

Notice what the framework does not do: it never tells you to self-host everything because self-hosting is virtuous. Sovereignty is a goal pursued in proportion, not a mandate. A four-person startup with one Kafka topic should stay on the managed service and spend its scarce engineering time on the product; the calculus flips when the backbone becomes load-bearing, the bill becomes a headcount, and the team has the depth to own it. Getting that timing right — neither renting past the point it makes sense nor self-hosting before you are ready — is the actual skill.

GitOps the fleet, and design the exit ramp in

The operational win of the operator model is that the entire backbone becomes Git-managed state. A Kafka, its node pools, every KafkaTopic, and every KafkaUser are YAML in a repository, applied by the same GitOps controller that manages the rest of your clusters. A new topic is a pull request with a reviewer and an audit trail, not a click in a console. An ACL change is a diff. A broker version bump is a commit that the operator rolls out one pod at a time, respecting min.insync.replicas so the cluster never drops below quorum during the upgrade. This is what audit-grade rigor looks like for streaming infrastructure: every change to who-can-read-what and what-topics-exist is reviewable, reversible, and attributable.

The exit ramp must be designed in before you need it — the day you need it is the worst day to find it missing. Concretely: keep producers and consumers on the open Kafka or NATS protocol and off vendor-only client extensions; hold your retention in an object store you own rather than a provider's opaque tier; pin schemas in a registry you run; and rehearse the failover you claim to have. Because all three engines here are open and protocol-compatible, moving between them — Confluent to Redpanda, self-hosted Kafka to another cluster, one region to another — is a mirror-and-cutover, not a rewrite. That property is the whole reason to do this: not to save a line item this quarter, but to never again be where leaving is too expensive to contemplate.

The long-game framing is where it lands. An event backbone is a decade-scale commitment — the topics you define and the semantics your services assume outlive the team that wrote them. Building it on open protocols, on infrastructure you own, with its lifecycle in version control and its history in your own object store, is what lets it last without becoming a hostage negotiation at renewal time. The events themselves feed everything downstream, from real-time services to the sovereign lakehouse where they become analytics — so the backbone's sovereignty propagates to every system built on top of it. Own the wire, and you own the estate.

That is the sovereign event backbone: not the cheapest platform, but one on an open protocol, with lifecycle as code you review and history as data you hold. Strimzi, Redpanda, and NATS are mature and open. The decision that remains is the one this practice returns to — whether you own the systems you depend on, or keep renting the one every other system depends on.

§FAQ/Common questions

Frequently asked

Is self-managed Kafka on Kubernetes with Strimzi production-ready in 2026?

Yes. Strimzi is a CNCF Incubating project whose operator manages the full lifecycle of an Apache Kafka cluster as Kubernetes custom resources — broker and controller node pools, topics, users, ACLs, TLS, and rolling upgrades. It removed ZooKeeper support in 0.46.0 (KRaft-only since then), which halves the number of distributed systems you operate relative to the ZooKeeper era. Its later 1.0 release dropped the older CRD API versions and left `v1` as the only served API. It is used in production across regulated industries. The remaining requirement is organisational rather than technical: you need a platform team that will own day-2 operations — topic design, ACL governance, consumer-lag monitoring, and capacity planning. The operator removes the toil of running Kafka on Kubernetes; it does not remove the need to understand Kafka.

How much cheaper is self-hosting Kafka than Confluent Cloud?

It depends heavily on scale, and infrastructure cost is only part of the picture. AxonOps' 2026 analysis put a 3-broker, 45 MB/s cluster at roughly $571/month self-hosted versus $1,216/month on Confluent Cloud, and a 30-broker, 1.875 GB/s workload at about $8,820/month versus a $42,093–$53,773/month Confluent Cloud range — the gap widens sharply with scale, driven largely by per-GB egress fees. But infrastructure-only figures exclude labour: once you price the engineering time to operate Kafka reliably, other analyses put managed services at roughly 3–5× lower total cost of ownership for teams without existing platform depth. The honest conclusion: self-hosting wins decisively at scale for a team ready to own day-2 operations, and loses for a small team that would be better off spending that time on its product.

When should I choose Redpanda instead of Strimzi-run Apache Kafka?

Choose Redpanda when you want the Kafka wire protocol with the smallest possible operational footprint. Redpanda is a single C++ binary with no JVM and no ZooKeeper, using a thread-per-core architecture and per-partition Raft consensus; it comes up quickly without a JVM warm-up path, uses less memory, and ships a schema registry and HTTP proxy in-process. That makes it easier to build, sign, patch, and reason about — valuable for a team new to self-managed streaming. Choose Strimzi's Apache Kafka when you need the full ecosystem: Kafka Connect's connector library, Kafka Streams, MirrorMaker geo-replication, or existing Kafka-native tooling. Both implement the same wire protocol, so clients are interchangeable and the exit ramp between them is a configuration change, not a rewrite.

How is NATS JetStream different from Kafka, and when is it the better choice?

NATS is a lightweight messaging system: core NATS is high-performance pub/sub and request-reply, and JetStream adds replicated, file-backed persistence with acknowledgements and retention policies. It uses subject-based addressing rather than Kafka's partitions and runs as a single small Go binary, trivial to deploy at the edge. It is the better choice for service-to-service messaging, eventing, and control-plane traffic that never needed a durable, replayable, partitioned log. It is not a Kafka replacement for high-throughput analytical streaming or workloads that depend on Kafka Connect. Many sovereign estates run both: NATS as the lightweight nervous system and Kafka, via Strimzi or Redpanda, as the durable system of record. Synadia's benchmark puts NATS 59–87% below Amazon Kinesis on cost, since its default consumer model matches what Kinesis charges a premium for.

Does leaving Confluent Cloud require rewriting my applications?

No — if you have stayed on the open protocol. Strimzi-run Apache Kafka, Redpanda, and Confluent all implement the same Kafka wire protocol (Produce, Fetch, Metadata, consumer-group coordination), so producers and consumers connect to any of them without code changes. A migration is typically a mirror-and-cutover: stand up the new cluster, replicate topics with MirrorMaker or a comparable tool, repoint client bootstrap servers, and decommission the old cluster. The lock-in that does require work lives in proprietary layers above the protocol — fully-managed connectors, ksqlDB-specific features, or Stream Governance. The discipline that keeps the exit cheap is to stay on the open wire protocol, keep vendor-specific surface thin, and hold your retention and schemas in infrastructure you own.

self-managed Kafka Strimzi KubernetesStrimzi Kafka operator production cost vs ConfluentRedpanda Kafka-compatible single binaryexit Confluent Cloud self-hosted Kafka 2026NATS JetStream vs Kinesis self-hostedKafka broker lifecycle GitOps observability

Executive Briefing

Thirty minutes to clarify your infrastructure risk

Walk us through your vendor footprint and regulatory constraints. We will tell you honestly where sovereignty creates leverage — and where it does not. No pitch deck. No obligation.