Skip to content
On this page

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.