/ Docs

Project Structure

Convention-Based Directory Layout

Bounda uses a file-based convention system to discover and wire your domain. Place files in the expected directories and Bounda handles registration, type generation, and runtime orchestration automatically.

Root Directory

The default root directory is app/. You can change this with the rootDir option in bounda.config.ts:

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

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

Directory Overview

app/
  domain/
    order/
      order-placed.ts
      order-cancelled.ts
      commands/
        place-order.ts
        cancel-order.ts
        send-confirmation/
          index.ts
          notification-sender.console.ts
          notification-sender.email.ts
      policies/
        send-confirmation-on-order-placed.ts
      processes/
        order-lifecycle/
          index.ts
          on-order-placed.ts
          on-order-confirmed.ts
          on-order-fulfilled.ts
  read/
    order-summary/
      view.ts
      projections/
        order-placed.ts
        order-cancelled.ts
      queries/
        get-order-summary.ts
    order-catalog/
      view.ts
      projections/
        order-placed.ts
      queries/
        get-orders.ts
  .bounda/

Domain Directory

domain/<aggregate-name>/

Each aggregate gets its own directory under domain/. Event files live directly inside the aggregate directory. Subdirectories organize commands, policies, and process managers.

Events — domain/<aggregate-name>/<event-name>.ts

Event files define a Zod payload schema and an apply function that updates the aggregate state. They are discovered by the pattern **/domain/*/*.ts.

Commands — domain/<aggregate-name>/commands/<command-name>.ts

Command handlers validate input and emit events. For simple commands, use a single file. For commands with collaborators (external services, adapters), use a directory with an index.ts entry point.

Pattern: **/commands/{*.ts,*/index.ts}

Policies — domain/<aggregate-name>/policies/<description>.ts

Policies react to events and dispatch follow-up commands. Name them descriptively to reflect the reaction, for example send-confirmation-on-order-placed.ts.

Pattern: **/policies/{*.ts,*/index.ts}

Process Managers — domain/<aggregate-name>/processes/<process-name>/

Process managers coordinate long-running workflows across multiple events. Each process has an index.ts configuration file and on-<event-name>.ts handler files.

Pattern: **/processes/{*.ts,*/index.ts}

Read Directory

read/<view-name>/

Each view (read model) gets its own directory under read/.

Views — read/<view-name>/view.ts

The view.ts file declares the field schema for the read model table.

Projections — read/<view-name>/projections/<event-name>.ts

Projection handlers receive events and write to the read model using the projector API. Each projection file corresponds to one event type.

Pattern: **/read/*/projections/{*.ts,*/index.ts}

Queries — read/<view-name>/queries/<query-name>.ts

Query handlers define a payload schema, a repository function for data access, and a handler that shapes the response.

Pattern: **/read/*/queries/{*.ts,*/index.ts}

Generated Types

.bounda/

The output directory for all generated files. Created and updated by running npx bounda generate. Configured via the outputDir option (defaults to .bounda).

+types/

Generated type files appear in +types/ directories co-located with your domain files. Each concept (event, command, query, projection) gets its own type file. These files are auto-generated and should not be edited manually.

For example, defining domain/order/order-placed.ts produces domain/order/+types/order-placed.ts containing the Event.PayloadFunction, Event.ApplierArgs, and other typed interfaces used in your event file.

File Naming Conventions

ConceptFile NameExample
Events<event-name>.tsorder-placed.ts
Commands<command-name>.ts or <command-name>/index.tsplace-order.ts
Policies<event-reaction-description>.tssend-confirmation-on-order-placed.ts
Process managers<process-name>/index.ts (config), on-<event-name>.ts (handlers)order-lifecycle/index.ts
Viewsview.tsview.ts
Projections<event-name>.tsorder-placed.ts
Queries<query-name>.tsget-order-summary.ts

All file names use kebab-case.

Default File Patterns

These are the glob patterns Bounda uses to discover files. They can be overridden in bounda.config.ts:

ConceptPattern
Commands**/commands/{*.ts,*/index.ts}
Events**/domain/*/*.ts
Policies**/policies/{*.ts,*/index.ts}
Projections**/read/*/projections/{*.ts,*/index.ts}
Queries**/read/*/queries/{*.ts,*/index.ts}
Process managers**/processes/{*.ts,*/index.ts}

Note: Test files (**/*.test.ts, **/*.spec.ts), node_modules, .bounda, and +types directories are excluded by default.