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
| Type | Description |
|---|---|
string | Text values |
number | Numeric values (integers and decimals) |
boolean | True/false values |
json | Complex nested data stored as JSON |
Field Options
| Option | Description |
|---|---|
primaryKey | Marks the field as the primary key for the view |
required | The field must have a value (non-nullable) |
index | Create an index on this field for faster queries |
default | Default 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
indexon 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
jsonfield type is useful for nested data that does not need to be individually queried or indexed.
Related Concepts
- Projections — populate view data from events
- Queries — read data from views