
# Views

Views are saved, named configurations of how a table's records are filtered, sorted, grouped, and projected. Add them under a table's `views` array. A view operates in one of two modes: **JSON config mode** (declarative filters/sorts/fields/group-by) or **SQL mode** (a raw PostgreSQL `query`).

## View Properties

| Property             | Description                                                                                    |
| -------------------- | ---------------------------------------------------------------------------------------------- |
| `id`                 | Unique view identifier.                                                                        |
| `name`               | Human-readable view name.                                                                      |
| `isDefault`          | Boolean. When `true`, this view's configuration applies when no specific view is requested.    |
| `filters`            | Filter conditions (JSON config mode). See below.                                               |
| `sorts`              | Array of `{ field, direction }` sort rules (JSON config mode). `direction` is `asc` or `desc`. |
| `fields`             | Array of field names to include, in display order (JSON config mode).                          |
| `groupBy`            | `{ field, direction? }` grouping configuration (JSON config mode).                             |
| `query`              | Raw SQL for a PostgreSQL `VIEW` (SQL mode). When set, JSON config properties are not used.     |
| `materialized`       | Boolean. With `query`, create a `MATERIALIZED VIEW` that caches results. SQL mode only.        |
| `refreshOnMigration` | Boolean. With `materialized`, refresh the materialized view during migrations.                 |

## JSON Config Mode

Declarative — filter, sort, group, and choose columns without writing SQL.

```yaml
views:
  - id: active_high_priority
    name: Active — High Priority
    isDefault: true
    filters:
      and:
        - { field: status, operator: equals, value: active }
        - { field: priority, operator: equals, value: high }
    sorts:
      - { field: created_at, direction: desc }
    fields: [title, status, priority, assigned_to]
    groupBy: { field: status, direction: asc }
```

### Filters

A filter is either a single condition `{ field, operator, value }` or a boolean group combining conditions with `and` / `or` (which may nest):

```yaml
filters:
  or:
    - { field: priority, operator: equals, value: high }
    - { field: priority, operator: equals, value: urgent }
```

Common operators include `equals`, `greaterThan`, `lessThan`, and similar comparison operators. See [Validation](/en/docs/table-validation) for how filter fields are checked against the table.

## SQL Mode

For advanced reporting, provide a raw `query`. Set `materialized: true` to cache the results, and `refreshOnMigration: true` to keep the cache fresh across schema migrations.

```yaml
views:
  - id: monthly_revenue
    name: Monthly Revenue
    query: >
      SELECT date_trunc('month', created_at) AS month, SUM(amount) AS revenue
      FROM orders GROUP BY 1 ORDER BY 1
    materialized: true
    refreshOnMigration: true
```

:::callout
**Default view.** Mark exactly one view per table with `isDefault: true` to control what records appear when a consumer requests the table without naming a view. View ids and the single-default rule are validated at config time.
:::
