
# Search Overview

Sovrium search is **not a standalone feature domain**. It extends the schemas you already use: tables declare _what_ is searchable (field weights, indexing), and page components declare _how_ search behaves (engine, debounce, highlighting, result display). There is no top-level `app.search` config — configuration lives where it is used.

The backend is built entirely on PostgreSQL: Full-Text Search (`tsvector`/`tsquery`) plus the `pg_trgm` extension for fuzzy, typo-tolerant matching. No Elasticsearch, no Algolia, no external service — search stays inside your own database, in keeping with Sovrium's digital-sovereignty principle.

:::callout
Two distinct search layers exist. **Record search** (this page) queries table data through the `search` data-source mode and the four engines below. **Public-pages search** indexes static page _content_ via the `pageSearch` component — see [search-components](/en/docs/search-components#pagesearch). They are different features at different layers.
:::

## Search engines

A data source in `mode: 'search'` selects its backend with `searchEngine`. The same table can use different engines on different pages.

| Engine    | Where it runs            | Best for                                                                        |
| --------- | ------------------------ | ------------------------------------------------------------------------------- |
| `client`  | Browser JavaScript       | Small datasets already loaded in the page; instant, no round-trip. **Default.** |
| `fts`     | PostgreSQL FTS           | Server-side ranked relevance over indexed text; large datasets.                 |
| `trigram` | PostgreSQL `pg_trgm`     | Fuzzy matching and typo tolerance; partial/misspelled queries.                  |
| `hybrid`  | PostgreSQL FTS + trigram | FTS for relevance with a trigram fuzzy fallback; best of both.                  |

### `client` — browser filtering

JavaScript filtering in the browser. The records are already fetched, and the query narrows them in-memory. Zero server round-trip, but the whole result set must fit in the page. Use it for small reference lists and pickers.

```yaml
- type: data-table
  dataSource:
    table: products
    mode: search
    searchFields: [name, description]
    searchEngine: client
    debounceMs: 300
```

### `fts` — PostgreSQL Full-Text Search

Server-side ranked search using `tsvector`/`tsquery`. Results come back ordered by relevance, weighted by each field's [`searchWeight`](/en/docs/full-text-search#field-relevance-weights). Requires the searched fields to be `indexed: true`. Use it for large, text-heavy datasets where ranking matters.

```yaml
- type: data-table
  dataSource:
    table: articles
    mode: search
    searchFields: [title, body]
    searchEngine: fts
    debounceMs: 300
    limit: 20
```

### `trigram` — fuzzy matching

Uses the `pg_trgm` extension to match on character trigrams, tolerating typos and partial words. Ideal when users misspell or type fragments (e.g. `prodct` still matches `product`). See [full-text-search](/en/docs/full-text-search#trigram-fuzzy-matching) for indexing details.

```yaml
- type: data-table
  dataSource:
    table: products
    mode: search
    searchFields: [name]
    searchEngine: trigram
```

### `hybrid` — relevance plus fuzziness

Combines FTS for relevance ranking with trigram as a fuzzy fallback, so exact and ranked matches surface first while misspelled queries still return results. The most forgiving engine for end-user-facing search.

```yaml
- type: data-table
  dataSource:
    table: products
    mode: search
    searchFields: [name, description]
    searchEngine: hybrid
    debounceMs: 300
    limit: 50
```

:::callout
`searchEngine` defaults to `client`. The `fts`, `trigram`, and `hybrid` engines run in PostgreSQL only — they require an indexed corpus. On SQLite, server-side ranking falls back to a simpler match; design index-backed search against Postgres. See [full-text-search](/en/docs/full-text-search#postgresql-vs-sqlite).
:::

## The `search` data-source mode

Search is one of three data-source modes (`list`, `single`, `search`). Setting `mode: 'search'` turns a data-bound component into an interactive, debounced search experience.

| Property       | Description                                                                                    |
| -------------- | ---------------------------------------------------------------------------------------------- |
| `table`        | Table to query (validated against `app.tables`).                                               |
| `searchFields` | Array (≥ 1) of field names to search across. Required for search mode.                         |
| `searchEngine` | Backend: `client` (default), `fts`, `trigram`, or `hybrid`.                                    |
| `debounceMs`   | Debounce delay for the search input in milliseconds (integer ≥ 0), e.g. `300`, `500`.          |
| `limit`        | Maximum number of results to return (integer ≥ 1), e.g. `10`, `20`, `50`.                      |
| `bindTo`       | ID of a `searchInput` component whose query drives this data source (cross-component binding). |
| `filter`       | Filter conditions (AND logic) applied alongside the search query.                              |
| `sort`         | Sort rules applied to results.                                                                 |
| `refreshMode`  | How results refresh after load: `none` (default), `poll`, or `realtime`.                       |

```yaml
# Interactive search with debounce and a result limit
- type: data-table
  dataSource:
    table: products
    mode: search
    searchFields: [name, description]
    searchEngine: hybrid
    debounceMs: 300
    limit: 20
```

For static filtering and ordering of non-search results, use the `list` mode with `filter`/`sort` instead — see [records-filtering-sorting](/en/docs/records-filtering-sorting).

## Choosing an approach

| Need                                                | Use                                                                          |
| --------------------------------------------------- | ---------------------------------------------------------------------------- |
| Narrow a small list already on the page             | `searchEngine: client`                                                       |
| Rank large text datasets by relevance               | `searchEngine: fts` + `indexed: true` + `searchWeight`                       |
| Tolerate typos and partial words                    | `searchEngine: trigram`                                                      |
| Both relevance ranking and typo tolerance           | `searchEngine: hybrid`                                                       |
| Search static page content site-wide                | `pageSearch` component — see [search-components](/en/docs/search-components) |
| Define which fields are searchable and how weighted | Field-level config — see [full-text-search](/en/docs/full-text-search)       |

## Related

- [Full-Text Search](/en/docs/full-text-search) — field-level `fullTextSearch`, `indexed`, and `searchWeight`.
- [Search Components](/en/docs/search-components) — `searchInput`, `pageSearch`, `list`, `command`, and toolbar search.
- [Text Fields](/en/docs/text-fields) — the `rich-text` field's `fullTextSearch` flag.
- [Tables Overview](/en/docs/tables-overview) — base field properties including `indexed` and `searchWeight`.
