/ Docs

Configuration Reference

Overview

Every Bounda project requires a bounda.config.ts file at the project root. This file defines which aggregates exist, how their event stores and read models are wired, and what runtime behavior to apply for policies and process managers.

import type { Config } from "@bounda-dev/config";

export default {
  domain: { /* ... */ },
  read: { /* ... */ },
} satisfies Config;

The Config type is the top-level interface. Bounda merges your configuration with sensible defaults at boot time.

Top-Level Options

OptionTypeDefaultDescription
domainRecord<string, DomainConfig>{}One entry per aggregate, keyed by aggregate name
readRecord<string, ReadConfig>{}One entry per read model, keyed by read model name
rootDirstring"app"Root directory containing your domain and read model files
outputDirstring".bounda"Directory where generated types are written
commandPatternstring"**/commands/{*.ts,*/index.ts}"Glob pattern for discovering command files
eventPatternstring"**/domain/*/*.ts"Glob pattern for discovering event files
policyPatternstring"**/policies/{*.ts,*/index.ts}"Glob pattern for discovering policy files
projectionPatternstring"**/read/*/projections/{*.ts,*/index.ts}"Glob pattern for discovering projection files
queryPatternstring"**/read/*/queries/{*.ts,*/index.ts}"Glob pattern for discovering query files
processManagerPatternstring"**/processes/{*.ts,*/index.ts}"Glob pattern for discovering process manager files

Domain Configuration

Each key in domain corresponds to an aggregate directory name. The value is a DomainConfig object:

interface DomainConfig {
  readonly eventStore: EventStoreConfig;
  readonly scheduling?: SchedulingConfig;
  readonly commands?: Record<string, CommandConfig>;
  readonly policies?: PoliciesConfig;
  readonly processManagers?: ProcessManagersConfig;
}

Event Store

Every aggregate requires an event store adapter. See the Adapters section for available types.

eventStore: { type: "in-memory" }
eventStore: { type: "sqlite", path: "./db/events.db" }
eventStore: { type: "postgresql", url: process.env.DATABASE_URL, schema: "bounda" }

Scheduling

Scheduling enables delayed and scheduled commands for an aggregate.

scheduling: {
  type: "sqlite",
  path: "./db/scheduler.db",
  pollingIntervalMs: 100,
}
OptionTypeDefaultDescription
type"sqlite" or "postgresql"Storage adapter for the scheduler
pathstringFile path (SQLite only)
urlstringConnection URL (PostgreSQL only)
schemastringDatabase schema (PostgreSQL only)
pollingIntervalMsnumberHow often to poll for due commands, in milliseconds
startWorkerbooleanWhether to start the scheduling worker automatically

Commands

The commands map lets you inject collaborator bindings into specific command handlers.

commands: {
  sendConfirmation: {
    notificationSender: { use: "console" },
  },
  sendWelcomeEmail: {
    emailSender: {
      use: process.env.SEND_WELCOME_EMAIL_SENDER ?? "resend",
      apiKey: process.env.RESEND_API_KEY,
    },
  },
},

Each command entry accepts a map of collaborator names to bindings. A binding is either a plain string or an object with use plus additional properties passed to the collaborator factory.

Policies

interface PoliciesConfig {
  readonly retry?: PolicyRetryConfig;
  readonly dlq?: PolicyStorageConfig;
  readonly maxChainDepth?: number;
  readonly executionsTTL?: number;
}
OptionTypeDefaultDescription
retry.retryStrategy"none", "exponential", "linear", "fixed""exponential"Retry strategy for failed policy executions
retry.maxRetriesnumber3Maximum number of retry attempts
retry.timeoutnumber30000Timeout per execution in milliseconds
maxChainDepthnumber25Maximum depth of chained policy reactions before halting
executionsTTLnumber604800000 (7 days)Time-to-live for execution records in milliseconds
dlq.type"sqlite" or "postgresql"Storage adapter for the dead letter queue

Process Managers

interface ProcessManagersConfig {
  readonly timeout?: string;
  readonly retry?: ProcessManagerRetryConfig;
  readonly dlq?: ProcessManagerStorageConfig;
}
OptionTypeDefaultDescription
timeoutstring"7d"Maximum lifetime of a process manager instance (e.g., "7d", "24h")
retry.retryStrategy"none", "exponential", "linear", "fixed""exponential"Retry strategy for failed handler executions
retry.maxRetriesnumber3Maximum number of retry attempts
retry.timeoutnumber30000Timeout per execution in milliseconds
dlq.type"sqlite" or "postgresql"Storage adapter for the dead letter queue

Read Configuration

Each key in read corresponds to a read model directory name. The value specifies the storage adapter:

read: {
  "order-summary": { type: "sqlite", path: "./db/order-summary.db" },
  "users-directory": { type: "mongodb-memory", path: "./db/users-directory-mongo", dbName: "bounda" },
  "my-profile": { type: "postgresql", url: process.env.DATABASE_URL, schema: "bounda" },
}

See Adapters for details on each read model adapter type.

Complete Examples

Storefront (SQLite + In-Memory)

import type { Config } from "@bounda-dev/config";

export default {
  rootDir: "src",
  domain: {
    order: {
      eventStore: { type: "in-memory" },
      scheduling: {
        type: "sqlite",
        path: "./db/order-scheduler.db",
        pollingIntervalMs: 100,
      },
      commands: {
        sendConfirmation: {
          notificationSender: { use: "console" },
        },
      },
      policies: {
        maxChainDepth: 5,
        retry: { retryStrategy: "none" },
      },
    },
  },
  read: {
    "order-summary": { type: "sqlite", path: "./db/order-summary.db" },
    "order-catalog": { type: "sqlite", path: "./db/order-catalog.db" },
    "my-orders": { type: "sqlite", path: "./db/my-orders.db" },
  },
} satisfies Config;

This configuration uses an in-memory event store for fast iteration during development, SQLite for scheduling and read models, and disables policy retries while limiting chain depth to 5.

Onboarding (PostgreSQL)

import type { Config } from "@bounda-dev/config";

const schema = process.env.BOUNDA_SCHEMA ?? "bounda";

export default {
  domain: {
    user: {
      eventStore: {
        type: "postgresql",
        url: process.env.DATABASE_URL,
        schema,
      },
      scheduling: {
        type: "postgresql",
        url: process.env.DATABASE_URL,
        schema,
      },
      commands: {
        sendWelcomeEmail: {
          emailSender: {
            use: process.env.SEND_WELCOME_EMAIL_SENDER ?? "resend",
            apiKey: process.env.RESEND_API_KEY,
          },
        },
      },
      processManagers: {
        dlq: {
          type: "postgresql",
          url: process.env.DATABASE_URL,
          schema,
        },
      },
    },
  },
  read: {
    "users-directory": {
      type: "mongodb-memory",
      path: "./db/users-directory-mongo",
      dbName: "bounda",
    },
    "user-details": {
      type: "sqlite",
      path: "./db/user-details-read.db",
    },
    "my-profile": {
      type: "postgresql",
      url: process.env.DATABASE_URL,
      schema,
    },
  },
} satisfies Config;

This production-oriented configuration uses PostgreSQL for the event store, scheduling, and process manager DLQ. Read models mix adapters based on query needs: MongoDB-style queries for the users directory, SQLite for user details, and PostgreSQL for the profile view.

  • Adapters — Available storage adapters and their configuration
  • CLI Reference — Command-line tools for code generation and operations