Configuration
Passing brokers (and everything else) to every new Kafka({...}) call works, but a monorepo
with several entry points — a web server, a worker, a CLI script — usually wants one shared
source of truth instead. Kafka.fromConfig() fills in whatever a call omits from a
kafka.config.ts file:
// kafka.config.ts, at the repo root or a workspace root
import { defineConfig } from '@cookiemonsterdev/kafka-core';
export default defineConfig({
client: {
brokers: ['localhost:9092'],
},
});
// anywhere under that directory
import { Kafka } from '@cookiemonsterdev/kafka-core';
const kafka = await Kafka.fromConfig(); // brokers comes from the file
new Kafka() discovers the same file, but it loads a TS/JS config file through a deprecated
synchronous path and warns once per file. A kafka.config.json file loads synchronously with no
warning.
Discovery walks upward from the current directory and stops at the nearest .git,
pnpm-workspace.yaml, or workspace package.json — so pnpm --filter ./apps/worker start still
finds a kafka.config.ts at the monorepo root. It only runs when a call omits brokers, so
existing code that already passes brokers never gains a filesystem read. See
Config file for the full precedence and discovery rules.
Per-environment configs
There is no built-in env:/profile concept — a config file is plain TypeScript, so branch on
process.env directly:
import { defineConfig } from '@cookiemonsterdev/kafka-core';
const configs = {
development: { client: { brokers: ['localhost:9092'] } },
production: { client: { brokers: ['broker-1:9092', 'broker-2:9092', 'broker-3:9092'], ssl: true } },
};
export default defineConfig(configs[process.env.NODE_ENV ?? 'development']);
Sharing defaults across producer, consumer, and admin
producer, consumer, shareConsumer, and admin sections apply the same way, under whatever
each call passes directly:
export default defineConfig({
client: { brokers: ['localhost:9092'] },
producer: { lingerMs: 20, compression: 'gzip' },
consumer: { sessionTimeout: 45_000 },
});
kafka.producer(); // lingerMs 20, compression gzip
kafka.producer({ lingerMs: 0 }); // this call's lingerMs wins; compression gzip still applies
Debugging which config file loaded
kafka.configSource();
// { path: '/repo/kafka.config.ts', keys: { brokers: 'file', clientId: 'default', ... } }
path is null when no config file was used at all — useful for confirming a client that should
be reading brokers explicitly (in CI, say) never picked up a stray config file from an
unexpected parent directory.
Top-level await, or an async factory
Kafka.fromConfig() loads a config file that needs async work. On Node, the synchronous
constructor cannot load one — see Config file.