skip to content

Compare RecordNameStrategy and TopicRecordNameStrategy. What subject does each produce and when would you choose one over the other?

level: seniorimportance: must knowfreq 55%

answer

  1. RecordName = FQN only, topic-agnostic, shared
  2. TopicRecordName = <topic>-<FQN>, isolated per topic
  3. both enable multi-type-per-topic
  4. share vs isolate trade-off
  5. blast radius of a breaking change

basics

~10 s

RecordNameStrategy names the subject after the schema's fully-qualified record name, so it's topic-independent and shared across topics. TopicRecordNameStrategy prefixes that with the topic (<topic>-<fqn>), scoping the same record type per topic.

solid answer

~40 s

RecordNameStrategy uses the record's fully-qualified name (namespace + name, e.g. com.acme.OrderCreated) as the subject, ignoring the topic. That subject is global, so the same type used across many topics shares one evolution timeline. TopicRecordNameStrategy combines both: <topic>-<fully-qualified-record-name>, e.g. orders-com.acme.OrderCreated. Both allow multiple event types in one topic because each type maps to its own subject, avoiding the collision you'd get with TopicNameStrategy. Choose RecordNameStrategy when you want one canonical, organization-wide schema lineage per type regardless of which topic carries it. Choose TopicRecordNameStrategy when you want multiple types per topic but still want each type's evolution scoped (isolated) per topic, so the same type can differ between topics without forcing a single shared lineage.

go deeper

for a junior

Know the names map to FQN-only vs topic+FQN subjects; details optional.

for a middle

State both subject formats and that both allow multiple types per topic.

for a senior

Articulate the share-vs-isolate trade-off and pick correctly per scenario.

for a principal

Reason about blast radius, schema ownership/governance, and lineage drift when standardizing strategy across an org.

## The problem these solve The default `TopicNameStrategy` maps a topic's value to a single subject (`<topic>-value`). If you try to publish **two genuinely different record types** to one topic, both land in the same `-value` subject and the registry treats them as evolutions of one another — they will fail compatibility checks. The record-aware strategies break the subject out of the topic so multiple types can coexist. ## RecordNameStrategy `io.confluent.kafka.serializers.subject.RecordNameStrategy` derives the subject from the **fully-qualified record name** of the schema itself: - Avro: `<namespace>.<name>` (e.g. `com.acme.OrderCreated`) - Protobuf: the fully-qualified message name - JSON Schema: the schema's title / `$id`-derived name The topic is **not** part of the subject. Consequences: - The **same type used in many topics shares one subject** and therefore one evolution timeline and one set of compatibility rules. Define `com.acme.Money` once; every topic that carries it uses subject `com.acme.Money`. - You can put many types in one topic — each maps to its own subject by its FQN. ## TopicRecordNameStrategy `io.confluent.kafka.serializers.subject.TopicRecordNameStrategy` derives the subject as **`<topic>-<fully-qualified-record-name>`** (e.g. `orders-com.acme.OrderCreated`). It combines both axes: - Multiple types per topic: yes (FQN disambiguates). - Evolution is **scoped per (topic, type)** pair, so the same record type can evolve differently in two different topics without conflicting. ## Choosing between them | Goal | Strategy | |------|----------| | One topic, one type (default) | TopicNameStrategy | | Many types per topic, ONE global lineage per type | RecordNameStrategy | | Many types per topic, lineage isolated per topic | TopicRecordNameStrategy | Rule of thumb: **RecordNameStrategy = sharing** (a type means the same thing everywhere — maximum reuse, but a breaking change ripples to every topic using it). **TopicRecordNameStrategy = isolation** (each topic owns its copy of the type's lineage — safer blast radius, but the same logical type can drift between topics and you register more subjects). ## Edge cases - Both are typically configured on `value.subject.name.strategy`; keys can use them too but multi-type keys are rare. - With record-name strategies, the consumer's deserializer must be able to handle whichever type arrives — schema ID in the wire header resolves it, but downstream code must branch on type (e.g. an Avro union or `SpecificRecord` dispatch). - RecordNameStrategy makes a single schema change a cross-topic event: governance and ownership of that subject become organizational concerns. - A renamed namespace silently creates a *new* subject (new lineage), losing the old compatibility history.

  • With RecordNameStrategy, what is the risk of making a breaking change to a widely-used type?
    Because the subject is global, every topic carrying that type shares the one lineage, so an incompatible change can break producers/consumers across many topics at once — large blast radius.
  • How does a consumer know which type it just read when a topic holds multiple record types?
    The 5-byte wire header carries the schema ID; the deserializer fetches that exact schema and reconstructs the correct type, and application code dispatches on the concrete type (e.g. Avro union / SpecificRecord class).

saying these in an interview costs you the question

  • Saying RecordNameStrategy includes the topic in the subject (it does not).
  • Claiming TopicRecordNameStrategy shares one lineage across topics (it isolates per topic).
  • Asserting you can put many types in a topic with the default TopicNameStrategy without conflicts.
  • Treating the two record strategies as interchangeable — they differ exactly on share-vs-isolate.

context