/ Docs

Views

What is a View?

A view defines the schema for a read model. In an event-sourced system, the write side (aggregates, events) is optimized for recording state changes, while the read side is optimized for querying. Views bridge this gap by declaring the shape of data that consumers need to read.

Views in Bounda

Views live inside read/<view-name>/ and are defined in a view.ts file that exports a fields function describing the read model schema.

read/
  order-summary/
    view.ts
    projections/
      order-placed.ts
      order-confirmed.ts
    queries/
      get-order-summary.ts

Defining a View

The view.ts file exports a fields function that returns an object mapping field names to their definitions:

import type { View } from "@bounda-dev/core";

export const fields: View.FieldsFunction = () => ({
  id: { type: "string", primaryKey: true },
  customerId: { type: "string", required: true, index: true },
  status: { type: "string", required: true, index: true },
  total: { type: "number", required: true },
  placedAt: { type: "string", required: true },
});

Field Types

TypeDescription
stringText values
numberNumeric values (integers and decimals)
booleanTrue/false values
jsonComplex nested data stored as JSON

Field Options

OptionDescription
primaryKeyMarks the field as the primary key for the view
requiredThe field must have a value (non-nullable)
indexCreate an index on this field for faster queries
defaultDefault value when the field is not explicitly set

Read Adapter Configuration

Views are backed by a read adapter configured in bounda.config.ts under the read key. The adapter determines how and where the read model data is stored:

read: {
  orderSummary: {
    adapter: {
      type: "sqlite",
      path: "./db/order-summary.db",
    },
  },
}

Different views can use different adapters. This allows you to choose the storage technology best suited for each read model’s query patterns.

Guidelines

  • Design views around query needs, not around aggregate structure. A single view might combine data from events across multiple aggregates.
  • Use index on fields that are frequently used in query filters or sorting to improve read performance.
  • Keep views focused. If a view serves very different query use cases, consider splitting it into separate views.
  • The json field type is useful for nested data that does not need to be individually queried or indexed.