Kafka Producer
Kafka Consumer
Java API
Configuration Settings
Troubleshooting Kafka

How to get back Kafka producer and consumer configuration (Java API)?

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

With the plain Kafka Java client, there is no general public API that lets you ask a running KafkaProducer or KafkaConsumer for the full effective configuration map after construction. In practice, if you need to inspect configuration later, the reliable solution is to keep your own immutable copy of the properties you used to build the client.

What You Can and Cannot Read Back

When you create a producer or consumer, you pass a Properties object or a Map. Kafka validates those values, fills in defaults internally, and constructs the client.

What the public API gives back:

  • metrics
  • metadata-related operations
  • subscription and assignment state for consumers
  • transactional and lifecycle methods for producers

What it does not generally give back:

  • a public getConfig() method with all current client properties
  • a complete map of user-supplied values plus resolved defaults

That is why code that needs later inspection should treat the configuration object as application state, not something to recover from the client instance.

Keep a Snapshot Yourself

The simplest pattern is to copy the settings before construction and expose that snapshot for diagnostics.

java
1import java.util.Collections;
2import java.util.HashMap;
3import java.util.Map;
4import java.util.Properties;
5import org.apache.kafka.clients.consumer.ConsumerConfig;
6import org.apache.kafka.clients.consumer.KafkaConsumer;
7import org.apache.kafka.clients.producer.KafkaProducer;
8import org.apache.kafka.clients.producer.ProducerConfig;
9
10public class KafkaClients {
11    private final Map<String, Object> producerConfig;
12    private final Map<String, Object> consumerConfig;
13    private final KafkaProducer<String, String> producer;
14    private final KafkaConsumer<String, String> consumer;
15
16    public KafkaClients(Properties producerProps, Properties consumerProps) {
17        this.producerConfig = snapshot(producerProps);
18        this.consumerConfig = snapshot(consumerProps);
19        this.producer = new KafkaProducer<>(producerProps);
20        this.consumer = new KafkaConsumer<>(consumerProps);
21    }
22
23    public Map<String, Object> producerConfig() {
24        return producerConfig;
25    }
26
27    public Map<String, Object> consumerConfig() {
28        return consumerConfig;
29    }
30
31    private static Map<String, Object> snapshot(Properties props) {
32        Map<String, Object> copy = new HashMap<>();
33        for (String name : props.stringPropertyNames()) {
34            copy.put(name, props.getProperty(name));
35        }
36        return Collections.unmodifiableMap(copy);
37    }
38
39    public static void main(String[] args) {
40        Properties producerProps = new Properties();
41        producerProps.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
42        producerProps.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG,
43                "org.apache.kafka.common.serialization.StringSerializer");
44        producerProps.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG,
45                "org.apache.kafka.common.serialization.StringSerializer");
46
47        Properties consumerProps = new Properties();
48        consumerProps.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
49        consumerProps.put(ConsumerConfig.GROUP_ID_CONFIG, "orders");
50        consumerProps.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG,
51                "org.apache.kafka.common.serialization.StringDeserializer");
52        consumerProps.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG,
53                "org.apache.kafka.common.serialization.StringDeserializer");
54
55        KafkaClients clients = new KafkaClients(producerProps, consumerProps);
56        System.out.println(clients.producerConfig());
57        System.out.println(clients.consumerConfig());
58    }
59}

This pattern is boring, and that is exactly why it works well.

Why "Read It Back Later" Is Tricky

Many Kafka settings interact. Some are explicit, some are defaults, and some may be framework-generated. If the client exposed a map of "current" values, you would still need to answer a second question: did the value come from your code, from a default, or from the framework around Kafka?

Keeping your own snapshot preserves intent. That is usually what you want during debugging.

Frameworks Change the Picture

If you are using Spring Kafka, Micronaut, Quarkus, or another framework, the right place to inspect configuration is often the factory or application configuration layer, not the raw Kafka client. For example, in Spring Kafka the producer factory and consumer factory are the natural places to look because they own the configuration maps before the underlying clients are created.

The same principle applies in plain Java applications with dependency injection: store the properties in a configuration object, inject that object, and build clients from it.

Validate Instead of Reflecting

Sometimes you do not actually need every property back. You only need to confirm that a few critical ones were set correctly. In that case, explicit validation is better than reflective inspection:

java
1void validate(Map<String, Object> cfg) {
2    require(cfg, ProducerConfig.BOOTSTRAP_SERVERS_CONFIG);
3    require(cfg, ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG);
4    require(cfg, ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG);
5}
6
7void require(Map<String, Object> cfg, String key) {
8    if (!cfg.containsKey(key)) {
9        throw new IllegalStateException("Missing config: " + key);
10    }
11}

That approach keeps configuration handling deterministic and testable.

Common Pitfalls

  • Expecting KafkaProducer or KafkaConsumer to expose a full public config getter.
  • Relying on the mutable Properties object after construction and assuming it reflects internal Kafka state.
  • Logging secrets such as SASL passwords while debugging configuration.
  • Confusing valid config keys with live config values. Kafka exposes constant names, not a full runtime snapshot.
  • Looking at the client layer when a framework-created factory is the real source of truth.

Summary

  • Plain Kafka Java clients do not generally provide a public API to read back the full effective configuration.
  • The practical fix is to keep your own immutable snapshot of the properties used at construction time.
  • Store configuration in one place and inject it into client builders.
  • Validate critical keys explicitly instead of trying to recover them from client internals.
  • In framework-based apps, inspect the framework configuration layer rather than the raw client.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.