Kafka as a System of Record
Most companies use Kafka as a pipe that carries data from one place to another. A growing number trust it with something bigger: being the one place where the true, final version of their data lives. This guide explains what that means, when it works, and what it demands.
Imagine a bank. Inside its vault sits a ledger, a book in which every deposit and withdrawal is written in order and never erased. The mobile app, the monthly statement and the fraud dashboard are all convenient views, but if any of them disagree with the ledger, the ledger wins. It is the record everyone trusts.
Now imagine that instead of a paper ledger, the bank keeps that permanent, ordered list of everything that happened inside Kafka. Every other system, from the account balance page to the reporting warehouse, is built from it and can be rebuilt from it. That is what it means to use Kafka as a system of record.
This is a serious decision, and it is not right for everyone. In this guide we go step by step in plain language. We define the idea, see why Kafka’s design suits it, learn the settings that make data safe, and meet the tools for retention, schemas, views and recovery. We also cover privacy, security, monitoring, mistakes and real-world stories, so you can decide with open eyes.
1What Is a System of Record?
The phrase sounds formal, but the idea is simple: when two copies of the same fact disagree, which one do you believe?
The plain meaning
A system of record is the authoritative source for a piece of data. It is the place where the data is created or first captured, and the place that is considered correct when copies elsewhere differ. Other systems may hold copies for speed or convenience, but they are treated as secondary and can be refreshed or rebuilt from the record.
A land registry office holds the official record of who owns each plot. A bank keeps a copy of your deed, a real estate website shows a photo and a summary, and your lawyer has a folder. If any of these disagree about who owns the land, everyone goes back to the registry. The registry is the system of record, and the others are copies.
What a system of record must provide
It must not lose data
Once something is recorded, it stays recorded, even if machines fail or a whole data center goes dark.
It must be consistent
Facts must be recorded once, in a clear order, without silent duplicates or gaps.
It must keep what happened
For many uses, you need to know not only the current state but how it came about.
It must be readable
Other systems must be able to get the data out reliably, in bulk and continuously.
It must be controlled
Access, changes, retention and deletion must follow rules, and be provable to auditors.
It must be restorable
If it is damaged, there must be a tested way to bring it back.
The usual candidates
Traditionally, relational databases such as PostgreSQL, MySQL or Oracle serve as systems of record, because they offer strong transactions and rich queries. Document stores, key-value stores and even mainframes fill the role in other organizations. The question of this guide is whether a distributed event log, Kafka, can share or take over that role for some kinds of data.
“System of record” is about trust and authority, not about technology. Ask of any dataset: if this copy and that copy disagree, which one wins? The answer tells you where your system of record already is.
Why the question matters more with streaming
In older architectures, each application owned one database and other systems received nightly file copies. The question of which copy wins rarely came up, because the copies were clearly labelled as stale. Real-time streaming changes this. When many systems receive updates within milliseconds, each of them starts to look like a live source, and disagreements become visible and confusing. Naming one authoritative place, and making every other copy visibly derived from it, is what keeps a fast, connected organization from arguing with itself about facts.
It also affects daily work. Support staff need to know which screen to trust when a customer disputes a charge. Analysts need to know which table to reconcile against. Auditors need to know where to look for evidence. A clearly declared record answers all of these questions with one sentence, and that clarity is often worth more than any technical feature.
2The Log Is the Truth
To see why Kafka can play this role, you need to understand the one data structure at its core: the append-only log.
What a log is
A log is a list of records added one after another at the end, each with a position number called an offset. Records are never changed in place. New information is simply added. Anyone can read from any position and get exactly the same records in exactly the same order, again and again.
flowchart LR
A["Offset 0: account opened"] --> B["Offset 1: deposit 500"]
B --> C["Offset 2: withdrawal 120"]
C --> D["Offset 3: deposit 40"]
D --> E["Offset 4: next event will be added here"]
A ship’s logbook records events as they happen: departure, weather, course changes. Nobody tears out pages or rewrites earlier entries. To know where the ship is now, you read the book from the start, or from a marked page. The book itself is the truth, and the ship’s current position is something derived from it.
Why a log suits a record
- Order is explicit: the offset tells everyone exactly what came before and after, so there is no argument about sequence within a partition.
- Nothing is overwritten: the history of what happened is kept by default, which is what auditors and analysts want.
- Readers are independent: each reader keeps its own position, so a new system can start from the beginning without disturbing anyone.
- Replication is natural: copying a log to other machines is simply copying the same records in the same order.
- Rebuilding is possible: any view of the data can be recreated by replaying the log.
How Kafka organizes logs
Kafka groups records into topics. Each topic is split into partitions, and each partition is its own log stored on a broker and copied to other brokers. Producers append records, and consumers read them. Records with the same key go to the same partition, so all the events about one customer or one order stay in order together.
Order is guaranteed inside one partition, not across a whole topic with many partitions. Design your keys so that events that must stay in order share a key and therefore a partition.
Reading without consuming
A detail that surprises newcomers is that reading a record in Kafka does not remove it. In a traditional queue, a message disappears once someone takes it. In Kafka, the log stays put and each reader simply remembers its own position. Ten different teams can read the same events at their own pace, and a reader that is down for a day resumes where it stopped. This property is what lets one record serve an entire company, since adding a new reader costs the existing ones nothing and requires no change to the writers.
3Can a Streaming Platform Really Be a Database?
Engineers have argued about this for years. The honest answer is that it depends on what you ask the record to do.
The case for
Kafka replicates data across machines, keeps it on disk, can retain it as long as you choose, gives strict ordering per key, and supports transactions across partitions. A well-known 2017 article by Jay Kreps, one of Kafka’s creators, titled along the lines of “It’s okay to store data in Apache Kafka”, argued that these properties make it a sound place for durable data. Many organizations now do so for event streams that describe their business.
The case against
Kafka is not a general-purpose database. It has no built-in way to look up one record by any field, no joins written as ordinary queries, no secondary indexes and no row-level update. If you ask “what is the current address of customer 42?”, Kafka alone cannot answer quickly. You must build or use a view for that, which is why Kafka is usually paired with other systems.
| Need | Relational database | Kafka |
|---|---|---|
| Look up one record by any field | Excellent, using indexes | Not designed for it; use a derived view |
| Ad hoc queries and joins | Excellent | Limited; use stream processing or an external store |
| Update one row in place | Built in | Not applicable; append a new event instead |
| Full history of changes | Needs extra design | Natural |
| Feeding many systems in real time | Awkward | Excellent |
| Replaying the past to rebuild a view | Awkward | Natural |
| Very high write volume | Limited by one node in many designs | Scales by partitions |
| Multi-record transactions with rich constraints | Excellent | Limited to atomic writes across partitions |
A company’s minute book records every decision the board has made, in order. It is the authoritative record. But to find “who is the current treasurer?”, you would not read every page each time. You keep a separate list of officers, updated from the minute book. The minute book is the record, and the officers list is a view. Kafka plays the minute book, and something else plays the list.
The balanced view
The most useful way to think about it is this: Kafka can be the system of record for events, the durable stream of things that happened, while other databases serve as fast, queryable views of the current state. In this design, the log is the truth and the databases are caches you can rebuild. Some teams go the other way, keeping a database as the record and using Kafka as a pipe. Both are valid, and this guide helps you know which fits.
Kafka as the record works well when
- Your data is naturally a stream of events.
- Many systems need the same data, each in its own shape.
- History and replay are valuable to you.
- You want to add new consumers without touching old ones.
Think twice when
- You mostly need lookups and updates on individual rows.
- Your team has no experience running Kafka carefully.
- Rich constraints must be enforced across many records at write time.
- Deletion rules are strict and the design has no plan for them.
A middle path many teams take
In practice, few organizations go all the way in either direction. A common compromise treats Kafka as the record for facts that are naturally events, such as clicks, orders placed, payments received and devices reporting, while leaving slowly changing master data, such as the list of legal entities, in a database with strong constraints. The two are linked by change-data-capture so the log still carries every change. This gives most of the benefits of an event record without forcing awkward designs onto data that is really a set of rows.
Whatever you choose, be explicit and consistent. The worst outcome is ambiguity, where two systems each believe they are the authority for the same data, because then every disagreement becomes an argument with no way to settle it.
4Events Versus State
The biggest mental shift in this whole topic is moving from storing what things are to storing what happened.
Two ways to record the same facts
A state record says what is true now: “Account 42 has a balance of 420.” An event record says what happened: “Account 42 received a deposit of 500.” “Account 42 had 120 withdrawn.” “Account 42 received a deposit of 40.” From the events you can always compute the state. From the state alone, you cannot recover the events.
flowchart LR
E["Events in Kafka: deposit 500, withdraw 120, deposit 40"] --> V["Replay and add up"]
V --> S["State: balance 420"]
S -. "cannot rebuild" .-> E
A bank statement listing every transaction is the events. The single line “current balance 420” is the state. If you lose the statement, the balance is a mystery, because you cannot tell how you got there. If you lose the balance but keep the statement, you can add it up again.
Event sourcing
Event sourcing is the design style in which an application stores every change as an event, and treats the current state as something computed from those events. It is a natural companion to Kafka as a system of record. The events are appended to a topic, and services build their own current-state views by reading the topic.
What you gain
Built-in history
You can always answer “how did we get here?” and “what did we know last Tuesday?”
New views later
A question nobody thought of last year can be answered by replaying old events into a new view.
Reproduce bugs
Replay the exact events that led to a wrong result and watch what the code does.
Independent consumers
Billing, search, analytics and notifications each read the same events without knowing about each other.
What you must accept
- Mistakes are corrected by adding events: you do not edit history. A wrong deposit is fixed with a correcting entry, just like in accounting.
- Views are eventually consistent: a derived database may lag a little behind the log.
- Event design is important: events must be named and shaped carefully because they live for years.
- Reading current state needs a view: you plan for it from the start.
Write events in the past tense and in business language: “OrderPlaced”, “PaymentReceived”, “AddressChanged”. They should describe facts that already happened, not commands hoping to happen.
Facts, commands and notifications
Not everything sent through Kafka is a fact worth keeping forever. A command asks someone to do something, such as “please ship this order”, and may be refused. A notification tells others that something happened, often with minimal detail. A fact, or domain event, records what did happen with all the information needed to understand it later. A record topic should hold facts. Mixing commands and facts in one topic makes history confusing, because a reader cannot tell whether an entry describes something that happened or something that was merely requested. Keep them in separate topics with clear names.
5Making Data Durable
A system of record must not lose what it has been told. Kafka gives you the tools, but they must be set deliberately.
Replication: many copies
Each partition has several copies on different brokers, called replicas. One is the leader, which handles reads and writes, and the others are followers, which copy it. The number of copies is the replication factor. A replication factor of three is the common choice for important data, so two machines can fail without losing anything.
sequenceDiagram
participant P as Producer
participant L as Leader
participant F1 as Follower 1
participant F2 as Follower 2
P->>L: write event
L->>L: append to log
F1->>L: fetch and copy
F2->>L: fetch and copy
L-->>P: acknowledged after enough copies exist
The safe settings together
| Setting | Where | Safe choice for a record | Why |
|---|---|---|---|
| replication.factor | Topic | 3 (or more) | Survive more than one failure |
| min.insync.replicas | Topic or broker | 2 | Refuse writes when too few copies are up to date |
| acks | Producer | all | Wait for all in-sync copies before saying “done” |
| enable.idempotence | Producer | true | Retries never create duplicates within a session |
| unclean.leader.election.enable | Topic or broker | false | Never elect a leader that is missing acknowledged data |
| Rack or zone awareness | Broker | Spread replicas across zones | Survive the loss of a whole zone |
Important legal documents are signed in triplicate, and each copy is stored in a different building. A clerk announces “filed” only when at least two buildings have confirmed receipt. A fire in one building loses nothing. Kafka’s safe settings enforce the same discipline for events.
Why “unclean” elections are dangerous
If the leader fails and every up-to-date follower is also gone, Kafka can either wait for one of them to return, or elect an out-of-date replica as the new leader. The second choice keeps the partition available, but it discards events that were acknowledged but not yet copied. For a system of record, availability is not worth silently losing facts, so the setting that allows it should be off.
The disk and the flush
Kafka writes to the operating system’s memory first and flushes to disk in the background, relying on replication for safety instead of flushing every message. For most systems of record, three replicas in different zones are a stronger guarantee than forcing every write to disk on one machine. Some regulated environments add flush settings for extra assurance, at a cost in speed.
Durability settings live in several places: the producer, the topic and the broker. A single application with acknowledgement set to one, or a topic created with a replication factor of one, quietly breaks the guarantee. Audit the effective settings for every topic that acts as a record.
A worked story of a failure that does not lose data
Suppose a topic has three replicas on brokers one, two and three, with a minimum of two in sync and acknowledgement of all. A producer writes an event, and brokers one and two confirm, so the producer is told success. A moment later, broker one, the leader, loses power. Broker two holds the event, so it becomes the new leader, and the event is still there. Broker three catches up and joins as a follower. Nothing acknowledged was lost, and nobody had to do anything. If broker two had also failed before broker three caught up, the partition would stop accepting writes rather than accept them unsafely, and it would resume when a replica returned.
This behaviour is the reason the settings work as a set. Acknowledgement of all without a minimum of two could accept writes with only the leader alive. A minimum of two without acknowledgement of all would not check at all. Only together do they form a promise.
6Retention: Keeping Data as Long as You Need
By default, Kafka forgets old data after a while. A system of record must be told to remember, and it must be able to afford to.
The default is to expire
Most topics are created with a retention period, commonly seven days, after which old segments of the log are deleted. This suits data used as a temporary pipe. For a system of record, the retention must be long enough to match the business need, or infinite.
| Retention choice | What happens | Suitable for |
|---|---|---|
| Time-based deletion | Segments older than a set time are removed | Pipes and buffers |
| Size-based deletion | Oldest segments removed once the log exceeds a size | Bounded storage |
| Infinite retention | Nothing is deleted by age or size | Full event history as the record |
| Compaction | Only the latest record per key is kept | Current-state tables |
| Compaction plus deletion | Latest per key, and old ones removed after a time | State with limited history |
A company can shred its papers every seven days, keep them for seven years because the law says so, or keep them forever in an archive. Which one is right depends on how important the papers are. A system of record belongs in the archive tier, not the shredder tier.
The cost of forever
Keeping every event forever means storage grows continuously. Brokers with large local disks become expensive, and recovering a failed broker takes longer because more data must be copied. Two developments make this practical.
Cheap long-term storage
Recent data stays on fast broker disks, while older segments move to inexpensive object storage such as Amazon S3. Consumers still read them through Kafka. Tiered storage became generally available in Apache Kafka in the 3.x line, and several vendors offer their own versions.
Smaller records
Compressing batches and using compact serialization formats reduces the volume stored, sometimes by a large factor.
Keep only the latest per key
Where full history is not needed, compaction bounds growth to the number of distinct keys.
Decide retention for each topic based on its role. An audit-grade event topic might keep everything, while a topic of intermediate calculation results can safely keep a week. Do not apply one setting to all topics.
Retention and the consumer who comes back late
Retention also decides how long a slow or stopped consumer can be away. If a consumer is offline for longer than the retention period, the events it missed are gone, and it can no longer catch up by reading. For a record with infinite retention this cannot happen, which is another practical benefit. For other topics, alert when a consumer’s lag approaches the retention limit, since crossing it turns a delay into permanent loss for that reader.
7Log Compaction: Keeping the Latest Truth
Some records matter only in their latest form. Compaction lets Kafka keep the newest value for each key forever without keeping every past value.
How compaction works
In a compacted topic, Kafka runs a background cleaner that looks for keys that appear more than once. It keeps the most recent record for each key and discards older ones. The result is a topic that always holds at least the latest value for every key, which is effectively a table of current state stored as a log.
flowchart LR
subgraph Before
A1["cust-1: address A"] --> A2["cust-2: address B"] --> A3["cust-1: address C"] --> A4["cust-2: address D"]
end
subgraph After
B1["cust-1: address C"] --> B2["cust-2: address D"]
end
Before --> After
An address book gets a new page every time a friend moves. Over the years it is full of old pages. Tidying up means keeping only the latest page for each friend. You lose the history of previous addresses, but the book stays small and always tells you where everyone lives now.
Tombstones: deleting a key
To delete a key from a compacted topic, you write a record with that key and an empty value, called a tombstone. Compaction eventually removes the earlier records for that key, and after a configurable delay, the tombstone itself is removed. This is how “delete” works in a log that never edits in place.
When to compact and when to keep everything
| Question | Compacted topic | Full-history topic |
|---|---|---|
| Do you need every past change? | No, only the latest | Yes |
| Storage growth | Bounded by number of keys | Grows with every event |
| Best for | Reference data, profiles, settings, product catalogs | Transactions, orders, payments, audit events |
| Rebuilding a table view | Fast, since only current values are read | Slower, must replay all history |
| Time travel to an older state | Not possible after compaction | Possible |
Compaction is not instant, and it never touches the newest, still-active segment. Readers may see several records for a key until the cleaner catches up, so consumers must always treat later records as overriding earlier ones.
Many systems use both patterns together: a full-history topic of events as the true record, and a compacted topic derived from it holding the current state of each entity, ready for fast rebuilds of views.
8Schemas: Making Data Readable for Years
A record that lasts for years must still be understood by programs written years later. That requires disciplined data formats.
The problem of time
Kafka stores bytes and does not care what they mean. Six months from now, an event written today will be read by a program that did not exist yet. If the meaning of a field has changed, or the field has been renamed, that program will misread the data or crash. Since a system of record never throws history away, the old and new shapes of data live side by side in the same topic.
A family keeps letters in a shoebox over generations. Handwriting styles change, some letters are in old spellings, and place names have changed. A family historian needs a guide explaining how to read each period. A schema is that guide for events.
Schemas and the registry
A schema describes the fields of an event: names, types and which are required. Formats such as Avro, Protocol Buffers and JSON Schema let you define a schema and encode data compactly. A schema registry is a service that stores every version of every schema and gives each a numeric identifier. Each message carries only that small identifier, and readers look up the full schema when they need it. Confluent’s Schema Registry is the best known, and other compatible registries exist.
Compatibility rules
The registry can refuse a new schema version if it would break readers. This is one of the most valuable protections for a long-lived record.
| Mode | Meaning | Typical safe changes |
|---|---|---|
| Backward | New readers can read old data | Add optional fields with defaults, remove fields |
| Forward | Old readers can read new data | Add fields, remove optional fields |
| Full | Both directions work | Add or remove optional fields with defaults |
| Transitive variants | The rule is checked against all earlier versions, not only the last | Strongest protection for topics kept forever |
Add optional fields
New fields with sensible defaults let old data stay valid.
Use a transitive mode for records kept forever
Every version must remain compatible with every earlier one, since old events never go away.
Changing a field’s meaning
Reusing “amount” to mean cents instead of dollars is legal for the registry but disastrous for readers.
Renaming without a plan
Renames look like removal plus addition and break old readers. Use aliases or a migration event.
When a breaking change is unavoidable
Sometimes the model of the business changes so much that compatibility cannot be kept. The standard answer is to create a new topic with the new schema, and run a job that translates old events into the new form, or to keep both and let readers handle the version by name. Plan such migrations carefully, since the old topic remains the historic record.
Treat schemas like public contracts. Review changes through the same process you use for changes to a public API, since every consumer, now and in the future, depends on them.
Choosing a format
Avro is popular with Kafka because its schemas travel well and support clear evolution rules. Protocol Buffers are common in organizations that already use them for service calls, and they also handle evolution well through numbered fields. JSON Schema is friendlier to people and tools that already exchange JSON, though it is larger on the wire. Whichever you choose, the important thing is that a schema exists, is stored centrally and is checked before data is written. Pick one house style so that readers across the company do not need to handle several.
9Ordering, Keys and Consistency
A record is only useful if you can trust the sequence of facts. Kafka’s guarantee is precise, and you need to know exactly where it stops.
What Kafka guarantees
- Order within a partition: records appear in the order they were written, and every reader sees the same order.
- Durability after acknowledgement: with safe settings, an acknowledged record survives broker failures.
- Consistent reads: consumers read only data that has been copied to all in-sync replicas.
What Kafka does not guarantee
- Order across partitions: two events with different keys may be read in either order.
- Global uniqueness rules: Kafka does not check that “no two users have the same email” at write time.
- Read-your-own-write in views: a database built from the log may not yet show an event just written.
Each customer at a bakery has their own numbered ticket stream at their own counter. Within a counter, tickets are served strictly in order. But between counters, nobody promises that ticket 5 at the left counter is served before ticket 3 at the right. If two orders must be handled in sequence, they must go to the same counter.
Choosing keys wisely
The key decides the partition, and therefore what stays in order. For a system of record, the key should be the identity of the entity whose history matters: the account number, the order identifier, the customer identifier. All events about that entity go to one partition and remain in order. A poorly chosen key, such as a random value, spreads related events across partitions and destroys their order.
Enforcing rules without a central lock
Business rules such as “an account must never go below zero” are harder. Since Kafka only appends, the rule must be enforced by the process that writes the event. A common design is to have a single service own each entity, process commands for that entity one at a time, check the rule against its own view of the state, and only then append the event. Because all commands for one key land in one partition and are handled by one consumer at a time, the checks cannot race with each other.
flowchart LR
C["Command: withdraw 100 from account 7"] --> S["Owning service reads its state for account 7"]
S --> D{"Rule satisfied?"}
D -- "yes" --> E["Append event: MoneyWithdrawn"]
D -- "no" --> R["Append event: WithdrawalRejected"]
Two services writing conflicting events about the same entity, without a coordinating owner, is the classic way to end up with a corrupted record. Give each kind of entity exactly one writer or one owning service.
Idempotent handling of the same command
Because commands may be retried, the owning service should recognize a command it has already handled. A simple technique is to include a unique command identifier and remember the identifiers recently applied to each entity. If the same command arrives again, the service replies with the earlier outcome instead of appending a second event. This mirrors what payment providers do with their own request identifiers, and it turns retries from a risk into a routine event.
10Transactions and Exactly-Once Records
A record that contains duplicates or half-finished updates cannot be trusted. Kafka offers two features that protect against both.
Idempotent producers: no duplicates from retries
When a network hiccup hides an acknowledgement, the producer resends. Without protection, the same event could be stored twice. An idempotent producer labels each batch with a producer identity and a sequence number, so the broker recognizes and ignores repeats. It is enabled by default in recent client versions and should stay on for any system of record.
A cashier numbers each receipt. If a customer’s card machine hangs and the cashier presses “pay” twice, the payment provider sees the same receipt number twice and charges once. Sequence numbers turn a dangerous retry into a safe one.
Transactions: all or nothing across partitions
Sometimes several events must be recorded together. A money transfer produces “debited from A” and “credited to B”, and possibly a third event on a different topic. A transaction lets a producer write to several partitions and topics as one atomic unit. Consumers configured to read only committed data either see all the events or none of them.
Consume, process, produce
Stream processing applications often read events, transform them and write results. Kafka transactions can bundle the writing of results with the saving of the read position, so that after a crash and restart, the application neither loses events nor produces results twice. This is the basis of Kafka Streams’ exactly-once processing mode.
Begin
The application starts a transaction under a stable identity that survives restarts.
Read and compute
It reads input events and calculates the results.
Write results
It writes result events, possibly to several partitions, and adds its read position to the transaction.
Commit or abort
On commit, everything becomes visible together. On failure, an abort hides everything.
The limits of the guarantee
Exactly-once in Kafka covers the flow from Kafka to Kafka. It cannot make an outside system, such as an email service or a payment gateway, do something exactly once. For those side effects, you still need unique identifiers and duplicate checks in the receiving system. A system of record protects the record itself, and the outside world must be handled with care.
Even with exactly-once features, include a unique business identifier inside each important event. It costs almost nothing and gives you a second line of defence against duplicates from any source.
11Building Views: How You Ask Questions
The log records; views answer. This chapter shows how current state, search and reports are derived from the record.
The command and query split
An architecture style known as CQRS, short for command query responsibility segregation, separates the side that accepts changes from the side that answers questions. Changes are written as events to Kafka. One or more consumers read those events and build separate read-optimized stores: a relational database for lookups, a search index for text queries, a cache for speed, a warehouse for analysis.
flowchart TB
W["Applications write events"] --> K["Kafka topics: the system of record"]
K --> V1["Consumer builds a relational view"]
K --> V2["Consumer builds a search index"]
K --> V3["Consumer builds a cache"]
K --> V4["Consumer feeds the data warehouse"]
V1 --> Q1["Queries by account and customer"]
V2 --> Q2["Full-text search"]
V3 --> Q3["Fast lookups"]
V4 --> Q4["Reports and analytics"]
A newspaper archive holds every printed edition. From it, a librarian builds a subject index, a name index and a photo catalog. Each index answers a different kind of question quickly, yet if an index is damaged, the librarian rebuilds it from the archive. The archive is the record and the indexes are views.
Tools for building views
| Tool | What it does | Good for |
|---|---|---|
| Kafka Streams | A library for applications that read, transform and aggregate topics, keeping state in local stores | Real-time aggregates, joins and enrichments inside your own services |
| ksqlDB | A streaming database that lets you define views with SQL-like statements | Quick derived streams and tables without writing much code |
| Apache Flink | A stream processing engine with strong support for time and large state | Complex, high-volume streaming logic |
| Kafka Connect sinks | Ready-made connectors that copy topics into databases, search engines and object stores | Loading views into existing systems |
| Custom consumers | Your own services that read events and update a store | Special cases with unique logic |
Interactive queries
Kafka Streams applications keep state in local stores, and they can expose it so other services can ask questions directly, such as “what is the current count for this customer?”. This works well for many uses but ties the query path to the running application, so many teams still prefer a separate database for heavy querying.
Eventual consistency
A view lags behind the log by a small amount, often milliseconds to seconds. After a customer changes an address, the search index might show the old one for a moment. Design your screens and processes to handle this. A common trick is to return the new value in the response to the change, so the user sees it immediately even before the view updates.
Never let two teams treat two different views as competing sources of truth. If a database view is edited directly, changes made there will not appear in the log, and the record and the view will silently drift apart.
Choosing between views
Different questions call for different stores. If people ask “show me this customer’s orders”, a relational database with an index on the customer is ideal. If they ask “find products matching these words”, a search engine is the better fit. If a website needs a value in a millisecond, a cache or key-value store serves it. If analysts want to combine years of data, a warehouse or data lake is right. The record does not have to answer any of these itself, which is exactly why it can stay simple, stable and trustworthy while the views change as needs change.
12Replay: The Superpower of a Record
Because the log keeps history, you can rebuild any view, fix any bug and answer any new question by reading it again.
What replay means
Replay means creating a new consumer, or resetting an existing one, and reading from an earlier position, even from the beginning. Because each consumer group keeps its own position, this affects nobody else. The new reader simply goes through the history and builds whatever it needs.
A football match is recorded. Analysts can rewatch it from the start, tracking only the goalkeeper, or only passing patterns, questions nobody thought of during the live game. The recording is the record, and each analysis is a new view.
Common uses
New service, full history
A new fraud detection service starts from the earliest event and learns from years of past behaviour before handling live traffic.
Bug fix and rebuild
A calculation bug corrupted a view. After fixing the code, you discard the view and rebuild it from the log.
New question
Marketing wants a metric that was never tracked. Replaying history produces it for the whole past.
Technology change
You move from one database to another by loading the new one from the log and switching when it is caught up.
Audit and investigation
Reconstruct exactly what the system knew and did at a past moment.
Making replay practical
- Make consumers idempotent: replays mean the same event may be processed more than once, so repeated handling must be harmless.
- Watch side effects: replaying “send email” events would email customers again. Separate view-building logic from actions that affect the outside world.
- Plan for time: replaying years of data takes hours or days. Snapshots, compacted topics and parallel consumption shorten it.
- Keep event time: store the time the event happened inside the event, not only the time Kafka received it.
Rehearse a full rebuild of at least one important view at regular intervals. A replay that has never been practised often fails the first time it is really needed.
Replay across versions of your own code
A subtle point is that replaying history with newer code may produce different results from what the older code produced at the time. This is often the whole point, such as fixing a bug, but sometimes you need the historic result exactly as it was, for example when reproducing a past regulatory report. In that case, keep the version of the code, or the saved output, alongside the date. Treating the results of important calculations as events in their own right, written to the log at the time, gives you a faithful record of what the organization concluded then, separate from what it would conclude now.
13Backup, Disaster Recovery and Multiple Regions
Replication inside one cluster protects against machine failures. A true record also needs a plan for the loss of a whole site, and for human error.
Replication is not backup
Replicas copy everything, including mistakes. If someone deletes a topic or writes a wrong batch of events, all replicas obey. Replication protects against hardware trouble, while backup and recovery protect against disasters and mistakes. A system of record needs both.
Having three copies of a document on three computers in your office protects you from one computer breaking. It does not protect you from a fire in the office, or from you accidentally saving nonsense over the file on all three. Off-site copies and older versions are separate protections.
Two levels of failure
One availability zone fails
A cluster stretched across three zones with rack-aware replication keeps working, since each partition has copies in other zones.
An entire region fails
Needs a second cluster in another region with a continuously updated copy of the data.
Deleted or corrupted data
Needs access controls, protection against topic deletion, and a copy or archive that changes are not applied to instantly.
Cross-cluster replication
flowchart LR
subgraph Region A
KA["Primary Kafka cluster"]
end
subgraph Region B
KB["Standby Kafka cluster"]
end
KA -- "continuous copy" --> KB
KA --> AppA["Applications in Region A"]
KB -. "used after failover" .-> AppB["Applications in Region B"]
| Approach | How it works | Points to note |
|---|---|---|
| MirrorMaker 2 | Open-source tool in Kafka that copies topics and translates consumer positions between clusters | Copy is asynchronous, so a small amount of the newest data may be missing after a sudden failure |
| Cluster Linking | Confluent feature that mirrors topics between clusters keeping the same offsets | Simpler failover, offered by that platform |
| Stretch cluster | One cluster spanning several sites with synchronous replication | No data loss on failover, but higher latency and needs very reliable links |
| Archive to object storage | Copy events to cheap durable storage, such as files in a bucket | Protects against catastrophic errors; restore is slower |
Two numbers to agree on
Business owners should decide two targets. The recovery point objective is how much recent data you can afford to lose in a disaster. The recovery time objective is how long you can be without the system. Asynchronous copying between regions gives a small nonzero recovery point but is fast and cheap. Synchronous stretch designs can reach a recovery point of zero, at a cost in write latency.
A disaster recovery plan that has never been rehearsed is a hope, not a plan. Run failover exercises, measure the real recovery time and data gap, and fix what you learn.
Thinking about the size of the gap
With asynchronous copying, there is always a small window between a write in the primary region and its arrival in the standby. In normal conditions this may be a fraction of a second, but during heavy load or network trouble it can grow. Monitoring that gap continuously tells you your real, current recovery point. Some organizations also keep a periodic, immutable archive of all events in object storage with locks against deletion, as a last line of defence against catastrophic mistakes or malicious action.
14Privacy, Deletion and the Right to Be Forgotten
An unchangeable, permanent log collides with laws that say personal data must be deleted on request. This is the most delicate part of the whole subject.
The tension
Privacy laws such as the European GDPR give people the right to have their personal data erased under certain conditions. A log that keeps everything forever and never edits records seems to make this impossible. Yet organizations do meet these rules with Kafka, using several techniques. This is not legal advice, and your legal team should decide what your obligations are.
Techniques
Delete by key in compacted topics
Write an empty value for the person’s key. After compaction, earlier records with that key are removed.
Delete the key, not the data
Encrypt each person’s personal fields with a key unique to that person. To erase them, destroy the key, and the encrypted data becomes unreadable everywhere, including in backups.
Keep personal data out of events
Store only an identifier in the event, and keep the personal details in a separate, deletable store. Deleting the details leaves harmless identifiers behind.
Let it expire
For topics carrying personal data that need not be kept, use a retention period that matches your policy.
Rewrite a topic
Create a new topic without the person’s records, switch consumers to it and delete the old one. Heavy, but sometimes needed.
A hospital’s paper archive holds patient files in sealed envelopes, each locked with its own key. When a patient asks to be forgotten, the hospital destroys that patient’s key. The envelope is still on the shelf, but nobody can ever open it again. Crypto-shredding works in the same way, and it reaches every copy at once.
Designing for privacy from the start
- Classify fields: mark which fields are personal, so tools and reviews can treat them specially.
- Minimize: put only what is needed into events. A fact you never stored cannot leak or need deletion.
- Encrypt selected fields: field-level encryption protects personal data even from people with broad read access to a topic.
- Track where copies go: deletion must also reach views, search indexes and warehouses. The record helps by letting you see every consumer.
- Document your approach: auditors ask how deletion requests are honoured, and a clear design is your answer.
If your data contains a lot of personal information, decide the deletion method before the first event is written. Retrofitting encryption or separation into years of existing history is much harder.
15Security and Governance
A system of record holds the most valuable and sensitive data an organization has. It must be protected accordingly.
The layers of protection
Encrypt connections
Use TLS between clients and brokers and between brokers, so data cannot be read or altered on the network.
Prove identity
Require every client to authenticate with certificates or SASL credentials, tied to a specific application or person.
Limit what each identity can do
Use access control lists so each application can write or read only the topics it needs. Only the owning service may write to a record topic.
Encrypt data at rest
Encrypt disks or volumes so stolen drives or snapshots reveal nothing. Add field-level encryption for particularly sensitive values.
Protect administration
Restrict who can delete topics, change settings or read secrets. Consider requiring two people for dangerous actions.
Log and audit
Record who accessed and changed what, and keep those audit logs safe and tamper-evident.
A bank vault has a strong door, a guard who checks identity, separate keys for separate boxes, cameras and a logbook of every visit. No single measure is enough, and each guards against a different kind of failure. Securing a record uses the same layers.
Governance: who owns the record?
Technology alone does not make a good record. You also need clear ownership. Every record topic should have a named owning team, a documented schema, a stated retention and deletion policy, and a description of who may read it and why. Data catalogs and lineage tools help by showing where each topic comes from and which systems consume it. Without this, “the record” becomes a pile of topics that nobody dares to touch.
| Governance item | Question it answers |
|---|---|
| Owner | Who is responsible for this topic and its quality? |
| Schema and compatibility policy | What does each field mean and how can it change? |
| Retention and deletion policy | How long do we keep it and how do we erase personal data? |
| Access policy | Who can write it, who can read it, and why? |
| Lineage | Which systems produce and consume this data? |
| Classification | Is the data public, internal, confidential or regulated? |
Because a record is permanent, a mistake in what is written, such as a secret or a password put into an event by accident, is hard to remove. Validate and scan events before they are written, and never place credentials inside them.
Separating duties
A useful principle from finance applies well here: the people who can change the system should not be the only people who can approve or audit the changes. Give operators the ability to run the platform without granting them the ability to read every sensitive payload. Give application teams write access to their own topics only. Let a separate group review access requests. Small steps like these limit the harm from mistakes and from stolen credentials alike.
16Monitoring and Alerting
If Kafka is the record, then knowing its health, at every moment, is not optional. Small problems in a record become large problems years later.
The signals that matter most
| Signal | Why it matters for a record | Response |
|---|---|---|
| Offline partitions | Some data is unavailable to read or write | Page immediately |
| Under-replicated partitions | Fewer copies than intended, so less protection | Investigate quickly, page if it persists |
| Unclean leader elections | Acknowledged data may have been lost | Page and investigate; should be zero |
| Below minimum in-sync replicas | Writes with full acknowledgement are being refused | Page; restore replicas |
| Producer errors and retries | Applications may fail to record events | Alert on sustained errors |
| Consumer lag of view builders | Views are falling behind the record | Alert when lag exceeds what the business can accept |
| Disk and tiered storage usage | Retention forever needs capacity planning | Alert on growth trend, not just thresholds |
| Schema registry health | Producers and consumers depend on it to read and write | Treat it as critical infrastructure |
| Replication lag to standby cluster | Determines the real recovery point | Alert against your recovery objective |
A museum guards its treasures with sensors on every door and window, a temperature monitor and a regular inspection round. The guards do not wait for a theft to learn something is wrong. They watch small signs, such as an unlocked window, because losses from treasures are permanent.
Beyond metrics: checking correctness
Health metrics tell you the platform is running. They do not tell you the data is right. Additional checks are valuable for a record: count events written at the source and events read at the destination and compare, run periodic reconciliation between views and the log, and validate a sample of events against their schemas and business rules. A steady reconciliation job that says “the view and the record agree” gives confidence that no quiet corruption exists.
Keep an audit trail of changes to topic settings, such as retention and replication. A record silently switched to a seven-day retention by a well-meaning script is a disaster that appears only later.
Runbooks and drills
Each alert on a record should link to a short page saying what it means, how serious it is and what to try first. For a record, add the questions that matter to the business: is any data lost, is any data unavailable, and who must be told. Practise these runbooks in drills where a broker is stopped or a zone is disconnected on purpose in a test environment. The first time an engineer follows a runbook should never be during a real incident at night.
17Performance and Scalability
A record grows every day. Planning for its size, its speed and its recovery time is part of the design.
Storage planning
With long or infinite retention, storage needs equal the event rate times the event size times the retention time, times the replication factor for local disks. Compression and tiered storage lower this considerably. Estimate growth for several years, and remember that recovery and rebuild times increase along with the amount of stored data.
Recovery time
When a broker fails and is replaced, the new one must copy all the data of its partitions from other brokers. With many terabytes on each broker, this can take hours, during which the cluster has less redundancy. Tiered storage helps, since only the recent local part must be copied, and older data stays in object storage.
Partition planning
Partitions cannot be reduced later, and increasing them changes key placement. For a record where order per key matters, choose the partition count generously up front, based on your expected peak load and the number of parallel consumers you may need in the future, while avoiding extreme numbers that strain the cluster.
An archive room fills up every year. The librarian must plan for shelves ten years ahead, and also decide what would happen if the whole room needed to be moved. The bigger the archive, the longer moving takes. Growth planning and recovery planning are two sides of the same worry.
Replay speed
Rebuilding a view means reading a large history quickly. Reads of old data come from disk, or from object storage under tiered storage, and can compete with live traffic for resources. Run large rebuilds with quotas or on a separate consumer cluster, so they do not slow down live writers, and read partitions in parallel using enough consumer instances.
Use tiered storage for long history
Keeps brokers small and recovery quick.
Set quotas for replays
Prevent bulk rebuilds from harming live traffic.
Snapshot large views
Restore a recent snapshot and replay only the events since then.
Assuming today’s speed holds forever
A rebuild that takes an hour now may take a day in three years.
A record grows silently. Alert on growth rate and forecast when storage or recovery time will cross limits, so you act months before the problem becomes an emergency.
Keeping the cost visible
Because a record never shrinks, its cost belongs on a dashboard that leaders can see. Track total stored data, growth per month, the share on fast disks versus object storage, and the cost per topic. Topics that grow unexpectedly, perhaps because a producer began sending duplicate or oversized events, then show up early. Reviewing these numbers each quarter, together with the teams that own the topics, keeps the record affordable and keeps surprises away.
18Patterns and Anti-Patterns
Teams that have run a Kafka-based record for years repeat certain designs and avoid certain mistakes.
Patterns worth copying
Event log as the record, databases as views
Write business events to Kafka first. Build every database, index and cache as a view fed from those events.
Why it works
Views can be replaced, corrected or added without touching the record, and all of them agree because they come from the same source.
Everyday picture
A city keeps its official map in the planning office. Tourist maps, transit maps and delivery maps are drawn from it and redrawn when it changes.
Transactional outbox for existing databases
If a service must keep its own database, write the business change and an outgoing event into the same database transaction, and let a change-data-capture tool such as Debezium publish the event to Kafka.
Why it works
It avoids the trap of updating a database and then failing to publish, or the reverse, and gives Kafka a reliable stream of events.
Everyday picture
A shop writes each sale and a “please notify accounting” slip in the same drawer at once. A clerk later carries every slip to accounting, so no sale is forgotten.
Single-writer ownership
Give each entity type exactly one owning service that validates commands and writes its events. Others read but never write those topics.
Why it works
Rules are enforced in one place, and conflicting writes cannot corrupt the record.
Everyday picture
Only the registrar signs certificates. Others may request or read them, but nobody else can issue one.
Snapshot plus replay
Periodically save a snapshot of a view along with the log position it reflects. To rebuild, restore the snapshot and replay only later events.
Why it works
Rebuild time depends on recent events, not on the whole history.
Everyday picture
Instead of re-reading a whole diary to learn where you left off, you keep a bookmark and read only the pages after it.
Anti-patterns to avoid
What people do
They declare Kafka the system of record but leave the default seven-day retention and a replication factor of one.
Why it hurts
Data expires or is lost with a single broker failure. The label says “record”, but the settings say “temporary”.
What to do instead
Set retention, replication, acknowledgement and election settings explicitly and audit them.
What people do
They write to their database and to Kafka in two separate steps, hoping both succeed.
Why it hurts
A crash between the steps leaves the two out of step, and nobody knows which is right. This “dual write” is one of the most common sources of corruption.
What to do instead
Use one source of truth, the log or an outbox, and derive the other from it.
What people do
They treat Kafka as a general database and query it directly for lookups by arbitrary fields.
Why it hurts
Scanning a topic to find one record is slow and expensive, and the design fights the tool.
What to do instead
Build a proper queryable view from the log and query that.
What people do
They publish events without schemas, or allow anyone to change them freely.
Why it hurts
Years later, nobody knows what old events mean, and consumers break unpredictably.
What to do instead
Register schemas, enforce compatibility and review changes as public contracts.
What people do
They put personal data into permanent events with no plan for deletion.
Why it hurts
When a deletion request arrives, there is no practical way to comply, and the organization is exposed legally.
What to do instead
Minimize personal fields, encrypt them per person or separate them, and document the erasure method.
19Best Practices and Common Mistakes
A compact list of habits that keep a Kafka-based record trustworthy, and traps that catch many teams.
Do
- Decide explicitly which data Kafka is the record for, and write it down.
- Use replication factor three, minimum in-sync replicas of two and acknowledgement of all.
- Turn off unclean leader election on record topics.
- Set retention deliberately, and use tiered storage for long histories.
- Register schemas and enforce strict compatibility.
- Choose keys that represent the entity whose history must stay in order.
- Give each entity type one owning writer.
- Make every consumer idempotent and safe to replay.
- Plan deletion and encryption of personal data before the first event.
- Rehearse disaster recovery and view rebuilds regularly.
- Restrict topic deletion and configuration changes, and audit them.
Do not
- Assume defaults are safe for a record.
- Write to a database and to Kafka separately and hope they match.
- Edit views directly and let them drift from the log.
- Store secrets or unneeded personal data in events.
- Rely on replication alone as your backup.
- Query the log for lookups instead of building a view.
- Change the meaning of existing fields.
- Let several teams write to the same record topic.
- Skip monitoring of replication and elections.
- Choose Kafka for data that is really a set of rows updated in place.
Mistakes teams meet first
Forgetting that topics have their own settings
A topic created automatically by an application may take default retention and replication, silently unfit for a record. Disable automatic topic creation and create record topics through reviewed automation.
Confusing “acknowledged” with “safe”
Acknowledgement of one only means the leader has it. A leader failure right after loses the event, even though the producer was told success.
Expecting global order
Events across different keys arrive in unpredictable order, and logic that assumes otherwise fails rarely but painfully.
Unbounded growth surprises
Nobody forecast storage, and the cluster fills up years later during a busy period.
Replaying side effects
A rebuild re-sends emails or re-triggers payments because logic that acts on the outside world was mixed into view-building code.
Poorly named events
Events called “update” or “data changed” say nothing about intent. Years later, nobody can tell what happened.
No owner for old topics
The original team moved on, and nobody is willing to change or delete anything. Assign ownership as part of governance.
Running a national archive is not about buying the biggest shelves. It is about rules for what is accepted, how it is labelled, who may read it, how it is copied and how it is finally destroyed. Technology matters, but disciplined habits keep the archive trustworthy across decades.
A decision checklist before you commit
Is the data event-shaped?
Orders placed, payments made, sensors read. If yes, it fits naturally.
Do many systems need it?
The more consumers, the more Kafka’s fan-out and replay pay off.
Can you live with eventual consistency in views?
If a screen must always show the newest value instantly, plan how.
Is there a deletion plan?
Especially for personal data.
Does the team have the skills?
Operating a record needs solid Kafka knowledge, monitoring and rehearsed procedures, or a managed service that provides them.
20Real-World Stories
Public talks and articles from well-known organizations show the idea in practice. Details may have changed since they were published.
The New York Times and its content archive
The New York Times has described in public engineering talks how it stores its published content, going back to its earliest articles, as a log in Kafka. Every new article version is appended, and search, website and other systems build their own views from that log. The approach lets them add new consumers and rebuild views by replaying the log, which is the pattern at the heart of this guide.
LinkedIn and the log at the center
Jay Kreps, who helped create Kafka at LinkedIn, wrote a widely read essay describing the log as the unifying idea behind data systems. LinkedIn used Kafka as the central stream that feeds search indexes, caches, analytics and other stores, where each is a view of the log. That thinking shaped the whole event-streaming movement.
Confluent and the “okay to store data” argument
Confluent, the company founded by Kafka’s creators, has published articles arguing that storing data long-term in Kafka is legitimate when it is configured correctly, with replication, retention and compaction. It also built tiered storage and other features to make long retention affordable, which shows how the platform grew to meet this use.
Banks and event sourcing
Several banks and payment companies have spoken at public conferences about using Kafka as the backbone for event-driven core systems, with events representing accounts, payments and transfers. They stress strong durability settings, strict schemas and disaster recovery across regions. The exact designs differ, and most keep relational databases for queries and reporting.
Debezium and the outbox pattern
The open-source Debezium project, which captures changes from databases into Kafka, documents the outbox pattern in detail. Organizations with existing databases use it to publish reliable events without giving up the database they trust, moving gradually toward events as the shared record.
Managed platforms and long retention
Services such as Confluent Cloud, Amazon MSK and Aiven provide managed Kafka, and some offer tiered or infinite storage. They take over machine operations, but the customer still owns schema design, keys, retention choices, privacy and consumers, which are the parts that decide whether the record is trustworthy.
Lessons repeated across stories
Across public accounts from these organizations, a few lessons repeat. First, the change is as much cultural as technical, since teams must accept that history is kept and mistakes are corrected by adding events. Second, a small number of well-owned topics beat a sprawl of unowned ones. Third, the investment in schemas, monitoring and rehearsed recovery pays for itself the first time something unexpected happens. Finally, few organizations use Kafka alone, and most pair it with databases that serve queries.
21Frequently Asked Questions
Short answers to questions that newcomers and experienced engineers ask often.
22Summary and Key Takeaways
If you keep only one page of this guide, keep this one.
A system of record is the place whose version of the truth wins. Kafka’s replicated, ordered, append-only log can play that part for event data, provided you configure it for durability, keep data as long as needed, control the shape of events with schemas, and plan for recovery, privacy and security. Databases, search indexes and caches then become views that can be rebuilt from the log. The reward is flexibility, history and replay. The price is discipline.
Key Takeaways
- A record is about trust. It is the copy everyone believes when copies disagree, and everything else can be rebuilt from it.
- The log is the natural shape of truth. Ordered, append-only events keep history and let any reader start from any point.
- Kafka records events, views answer questions. Pair the log with databases and indexes built from it, instead of querying the log directly.
- Configure for durability. Three replicas, minimum two in sync, acknowledgement of all, idempotence on and unclean elections off.
- Set retention on purpose. Use long or infinite retention with tiered storage for history, and compaction for current state.
- Treat schemas as contracts. A registry and compatibility rules keep years of events readable.
- Choose keys and owners carefully. Order holds only within a partition, so one owning writer per entity keeps the record consistent.
- Plan recovery and privacy early. Replication is not backup, and permanent logs need a deletion design such as crypto-shredding.
- Watch it and rehearse it. Monitor replication, elections and lag, reconcile views, and practise failovers and rebuilds.
- Use it where it fits. Event-shaped data with many consumers is a strong match. Row-oriented data updated in place often belongs in a database.