Vantage UI

# Features

Use Vantage to build your own data-heavy applications. Vantage stores its project files in a folder, constantly monitoring them for changes — so the app can be easily modified from the outside.

## Your app = structure + code

Menu items, page layout and widget types are described in **YAML**. Custom logic and behaviour live in **Rhai**. The project folder also ships **.skills** that teach your AI coding agent to write both.

YAML — structure

```
# table/clients.yaml
title: Clients
source: main_db
columns: name, email, balance
has_many:
  - orders
context_menu:
  - title: View orders
    open_page: orders
    model: model.get_ref("orders", row.id)
```

Rhai — logic

```
// a computed label for each row
let label = row.name;
if row.balance < 0 {
    label += "  •  owes " + row.balance;
}
label

// drill two hops, in one expression
model.get_ref("clients", row.id)
     .get_ref("orders", client_id)
```

When a file changes on disk, Vantage re-reads it and the UI updates live.

## Tables (or Models) and DataSources

Vantage needs a **DataSource** to read data. Each DataSource has a unique set of **capabilities**. Once a connection is established, Vantage reads **tables** to learn about columns, record types and relations. **Enterprise** builds can also define strongly typed tables in **Rust**.

CSV files SQLite PostgreSQL MySQL SurrealDB MongoDB REST API GraphQL CLI command Kubernetes AWS Sample data In-memory tables

### SurrealDB

Read / write CBOR

[SurrealDB](https://surrealdb.com) [Vantage driver](https://docs.rs/vantage-surrealdb) [SurrealQL](https://surrealdb.com/docs/surrealql)

Full querying, aggregation, pagination, related columns and dataset-level traversal, with relations you can define in Rhai. Tables update themselves when data changes, through LIVE queries — nothing to set up.

Retrieving data

| Filter by conditions (Narrow the available table rows by applying one or more conditions. `table("order").where("status", "open")`) | Supported

| Conditional operators (Non-exact matching with basic operators such as `>`, `<` or `!=`. Full support also needs matching against a set of values (`in`) and fuzzy text matching (`contains`). `table("order").where("total", ">=", 100)`) | Supported

| Server-side sort (The server re-arranges the results, respecting each column's data type, ascending or descending, on several columns in a set priority. `table("order").sort("total", "desc")`) | Supported

| Quick search (A text search across several columns, performed on the server, so it can cover the entire table. `table("client").search("smith")`) | Supported

| Count (The server can say exactly how many rows remain in the set once the conditions are applied. `table("order").where("status", "due").count()`) | Supported

| Column aggregates (Aggregate functions applied to a column of a filtered set. The backend supports at least some of them, such as `max`, `avg`, `median` or a string concatenation (`group_concat`). `select().from("order").expression(avg(ident("total")).alias("avg_total")).expression(max(ident("total")).alias("max_total"))`) | Supported

| Random-access pages (Skip any number of rows in a filtered set without a performance penalty, and request any number of records up to a maximum. `select().from("order").order_by(ident("id"), "asc").limit(50, 1000)`) | Supported

| Progressive (cursor) load (A fall-back way to paginate: pages are sequential, and the next page can be fetched only after the previous one.) | Supported

Relations

| One-to-many relations (Only needs a filter by condition whose value comes from a record loaded from another table — in the same data source or a different one. `table("client").where("id", "c1").ref("orders")`) | Supported

| Many-to-many relations (A condition can be an expression over another set, such as a subquery or a join. Partial support when the `in` operator can match against a set of values. `table("client").where("country", "UK").ref("orders")`) | Supported

| Relation aggregation (A column can be defined as an aggregate of a field or expression in a related table, calculated on the server. The classic example is `account.balance` as the sum of `transaction.amount`. `// invoice.paid: the sum of its payments coalesce(select().value().from("payment").expression(sum(ident("amount"))).where(ident("invoice") == parent("id")).group_all().subquery()0, 0)`) | Supported

| Arbitrary expressions (Per-row operations on the server, over stored values or relation aggregates — for example `invoice_line.total` as `qty * item.price`. `mul(ident("qty"), ident("price")).alias("total")`) | Supported

| Column from related table (Import a field through a one-to-one relation, such as `country_id.name`, as a read-only column. `columns: client.name: { type: string }`) | Supported

| Contained record expressions (A condition can iterate over sub-records stored inside a record — invoices whose JSON `lines` field contains item `123`. `self.with_condition(#{"lines.item_id": 123})`) | Supported

| Relations defined in Rhai (Executes arbitrary code after a row is retrieved from the table, in the context of the entire row — a Rhai `lazy:` script in YAML, or a Rust closure that can also do I/O. `badge: lazy: | if row.vip { "★ " + row.name } else { row.name }`) | Supported

Live updates

| Record changed (An open record updates in place when someone else changes it — the source pushes the change, no polling.) | Supported

| Record set changed (A filtered grid updates when rows matching its condition change, and a row that stops matching leaves the grid.) | Supported

| Table changed (Any insert, update or delete in the table reaches open grids as it happens.) | Supported

| Related record changed (A change in a related table — an `invoice_line` — reaches the parent's view, such as `invoice.total`.) | Not supported

Editing data

| Add records (Create rows from a form dialog. In a filtered view, new rows are filled in to belong to it. `table("order").insert(#{ id: "o10", client: "c3", total: 55 })`) | Supported

| Update records (Edit rows in a form dialog. A write through a filtered view can never change a row outside it. `table("order").patch("o1", #{ status: "paid" })`) | Supported

| Delete records (Remove rows, after a confirmation step, from a grid or a record view. `table("order").where("status", "paid").delete("o2")`) | Supported

| Atomic import (A CSV or wizard import lands in one transaction: either every new row is stored or none is, and existing rows are left untouched. `let paid = table("order").where("status", "paid"); table("archive").import_from(paid)`) | Not supported

| Bulk modify (Change every row of a filtered set in one operation — mark all open orders as shipped — without loading them first.) | Not supported

Custom tables

| Tables from custom queries (A table can be defined by a query instead of a stored table — a Rhai script or a native query — and is read-only. `select().from("order").inner_join("client", "c", expr("c.id = order.client_id"))`) | Supported

| Table aggregate (A table defined through another table — sales grouped by month, built on orders — inheriting its columns and relations. `name: category_totals id_column: category_id columns: total_price: { type: int } sqlite: base: product inherit: columns: category_id rhai: | base.clear_fields().field("category_id").expression(expr("SUM(price) AS total_price")).group_by(expr("category_id"))`) | Supported

| Server-side actions (An action runs inside the data source, such as a stored procedure or function, instead of in the app.) | Not supported

Misc

| Auto-ID (When the id column is flagged `auto`, an insert without an `id` asks the data source to assign one — auto-increment, a generated record id, an ObjectId — and returns it. Without the flag the app mints a UUIDv7 instead, so retries stay idempotent. `# order.yaml columns: id: { type: int, flags: id, auto } // Rhai — no id, so the data source makes one let id = table("order").insert(#{ client: "c2", total: 30 });`) | Supported

| Idempotency (By default, every write can be retried safely: a repeated insert or delete changes nothing, and writes through a filtered view stay inside it. An insert that relies on Auto-ID is the exception — retrying it adds a second row. `// run twice: same result table("order").upsert("o10", #{ client: "c3", total: 60 })`) | Supported

### SQLite

Read / write Native (sqlx)

[SQLite](https://sqlite.org) [Vantage driver](https://docs.rs/vantage-sql) [SQLite SQL](https://sqlite.org/lang.html)

Full SQL driver via sqlx — sort, search, aggregation, pagination, subquery traversal and columns from related tables.

Retrieving data

| Filter by conditions | Supported

| Conditional operators | Supported

| Server-side sort | Supported

| Quick search | Supported

| Count | Supported

| Column aggregates | Supported

| Random-access pages | Supported

| Progressive (cursor) load | Supported

Relations

| One-to-many relations | Supported

| Many-to-many relations | Supported

| Relation aggregation | Partly supported (From Rust (`Table::with_expression`), or as a column of a read-only `rhai:` / `base:` table. There is no `expr:` column in SQL YAML yet.)

| Arbitrary expressions | Partly supported (From Rust (`Table::with_expression`), or as a column of a read-only `rhai:` / `base:` table. There is no `expr:` column in SQL YAML yet.)

| Column from related table | Supported

| Contained record expressions | Not supported

| Relations defined in Rhai | Supported

Live updates

| Record changed | Not supported

| Record set changed | Not supported

| Table changed | Not supported

| Related record changed | Not supported

Editing data

| Add records | Supported

| Update records | Supported

| Delete records | Supported

| Atomic import | Not supported

| Bulk modify | Not supported

Custom tables

| Tables from custom queries | Supported

| Table aggregate | Supported

| Server-side actions | Not supported

Misc

| Auto-ID | Supported

| Idempotency | Supported

What stands out

- One file on disk — no server to run or credentials to manage.
- Related columns become correlated subqueries, so `client.name` sorts and filters like any column.
- Views built from a Rhai query, or derived from another table with `base:`, taking arguments from the page.
- JSON columns open as their own editable tables.

### PostgreSQL

Read / write Native (sqlx)

[PostgreSQL](https://www.postgresql.org) [Vantage driver](https://docs.rs/vantage-sql) [PostgreSQL SQL](https://www.postgresql.org/docs/current/sql-commands.html)

Full SQL driver via sqlx — sort, search, aggregation, pagination, subquery traversal and columns from related tables. The framework can also read live changes from a NOTIFY trigger you install; turning that on from the app is next.

Retrieving data

| Filter by conditions | Supported

| Conditional operators | Supported

| Server-side sort | Supported

| Quick search | Supported

| Count | Supported

| Column aggregates | Supported

| Random-access pages | Supported

| Progressive (cursor) load | Supported

Relations

| One-to-many relations | Supported

| Many-to-many relations | Supported

| Relation aggregation | Partly supported (From Rust (`Table::with_expression`), or as a column of a read-only `rhai:` / `base:` table. There is no `expr:` column in SQL YAML yet.)

| Arbitrary expressions | Partly supported (From Rust (`Table::with_expression`), or as a column of a read-only `rhai:` / `base:` table. There is no `expr:` column in SQL YAML yet.)

| Column from related table | Supported

| Contained record expressions | Not supported

| Relations defined in Rhai | Supported

Live updates

| Record changed | Not supported

| Record set changed | Not supported

| Table changed | Partly supported (Needs a LISTEN/NOTIFY trigger you install, and the app doesn't switch it on yet. Changes arrive as "re-read the table", without the changed row.)

| Related record changed | Not supported

Editing data

| Add records | Supported

| Update records | Supported

| Delete records | Supported

| Atomic import | Not supported

| Bulk modify | Not supported

Custom tables

| Tables from custom queries | Supported

| Table aggregate | Supported

| Server-side actions | Not supported

Misc

| Auto-ID | Supported

| Idempotency | Supported

What stands out

- Related columns become correlated subqueries, so `client.name` sorts and filters like any column.
- Views built from a Rhai query, or derived from another table with `base:`, taking arguments from the page.
- JSON columns open as their own editable tables.
- The framework reads live changes from a `LISTEN/NOTIFY` trigger you install.

### MariaDB

Read / write Native (sqlx)

[MariaDB](https://mariadb.org) [Vantage driver](https://docs.rs/vantage-sql) [MariaDB SQL](https://mariadb.com/docs/server/reference/sql-statements)

Full SQL driver via sqlx — sort, search, aggregation, pagination, subquery traversal, columns from related tables, transactional imports and relations scripted in Rhai. Tested on MariaDB 11; the same driver runs MySQL 8.

Retrieving data

| Filter by conditions | Supported

| Conditional operators | Supported

| Server-side sort | Supported

| Quick search | Supported

| Count | Supported

| Column aggregates | Supported

| Random-access pages | Supported

| Progressive (cursor) load | Supported

Relations

| One-to-many relations | Supported

| Many-to-many relations | Supported

| Relation aggregation | Partly supported (From Rust (`Table::with_expression`), or as a column of a read-only `rhai:` / `base:` table. There is no `expr:` column in SQL YAML yet.)

| Arbitrary expressions | Partly supported (From Rust (`Table::with_expression`), or as a column of a read-only `rhai:` / `base:` table. There is no `expr:` column in SQL YAML yet.)

| Column from related table | Supported

| Contained record expressions | Supported

| Relations defined in Rhai | Supported

Live updates

| Record changed | Not supported

| Record set changed | Not supported

| Table changed | Not supported

| Related record changed | Not supported

Editing data

| Add records | Supported

| Update records | Supported

| Delete records | Supported

| Atomic import | Supported

| Bulk modify | Not supported

Custom tables

| Tables from custom queries | Supported

| Table aggregate | Supported

| Server-side actions | Not supported

Misc

| Auto-ID | Supported

| Idempotency | Supported

What stands out

- Related columns become correlated subqueries, so `client.name` sorts and filters like any column.
- Bulk imports run in one transaction, match ids the way the column's collation does, and fire the same hooks as a single insert.
- Views built from a Rhai query, or derived from another table with `base:`, taking arguments from the page.
- `modify:` scripts add SQL conditions that YAML can't express: `self.with_condition(ident("total") > 100)`.
- JSON columns open as their own editable tables.
- No live updates: MariaDB has no push channel short of reading the binlog.

### MongoDB

Read / write BSON

[MongoDB](https://www.mongodb.com) [Vantage driver](https://docs.rs/vantage-mongodb) [MongoDB query operators](https://www.mongodb.com/docs/manual/reference/operator/query/)

Filters, sort and search push down to the server, including nested fields. Related columns run as $lookup joins, read-only views come from aggregation pipelines in YAML, and edits keep ObjectId, date and decimal types. On a replica set, tables update live through change streams and bulk imports run in one transaction.

Retrieving data

| Filter by conditions | Supported

| Conditional operators | Supported

| Server-side sort | Supported

| Quick search | Supported

| Count | Supported

| Column aggregates | Supported

| Random-access pages | Supported

| Progressive (cursor) load | Supported

Relations

| One-to-many relations | Supported

| Many-to-many relations | Partly supported (Matches with in against the related ids, fetched first — not as a subquery.)

| Relation aggregation | Not supported

| Arbitrary expressions | Not supported

| Column from related table | Supported

| Contained record expressions | Supported

| Relations defined in Rhai | Supported

Live updates

| Record changed | Partly supported (Needs a replica set: change streams don't run on a standalone server.)

| Record set changed | Partly supported (Needs a replica set: change streams don't run on a standalone server.)

| Table changed | Partly supported (Needs a replica set: change streams don't run on a standalone server.)

| Related record changed | Not supported

Editing data

| Add records | Supported

| Update records | Supported

| Delete records | Supported

| Atomic import | Partly supported (Needs a replica set: the import runs in a transaction.)

| Bulk modify | Not supported

Custom tables

| Tables from custom queries | Supported

| Table aggregate | Not supported

| Server-side actions | Not supported

Misc

| Auto-ID | Supported

| Idempotency | Supported

What stands out

- On a replica set, tables update live through change streams — edits from any client appear in place.
- Read-only views from an aggregation pipeline written in YAML, or built by a Rhai script.
- `client.name` columns joined server-side with `$lookup`, several hops deep.
- Nested fields as columns — `nested_path: address.city` — searchable and filterable like any other.
- Embedded objects and arrays open as their own editable tables.
- Edits keep ObjectId, date and decimal types; `datetime` and `decimal` columns check what you type.
- Bulk imports run in one transaction and fire the same hooks as a single insert.
- Rhai filters are plain maps: `self.with_condition(#{price: #{"$gt": 100}})`.

### DynamoDB

Read-focused JSON

[DynamoDB](https://aws.amazon.com/dynamodb/) [Vantage driver](https://docs.rs/vantage-aws) [DynamoDB Query](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Query.html)

Key and scan-filter queries with cursor pagination. Often paired as a read source with writes routed elsewhere.

Retrieving data

| Filter by conditions | Supported

| Conditional operators | Not supported

| Server-side sort | Not supported

| Quick search | Not supported

| Count | Supported

| Column aggregates | Not supported

| Random-access pages | Not supported

| Progressive (cursor) load | Supported

Relations

| One-to-many relations | Supported

| Many-to-many relations | Not supported

| Relation aggregation | Not supported

| Arbitrary expressions | Not supported

| Column from related table | Not supported

| Contained record expressions | Not supported

| Relations defined in Rhai | Not supported

Live updates

| Record changed | Not supported

| Record set changed | Not supported

| Table changed | Not supported

| Related record changed | Not supported

Editing data

| Add records | Not supported

| Update records | Not supported

| Delete records | Not supported

| Atomic import | Not supported

| Bulk modify | Not supported

Custom tables

| Tables from custom queries | Not supported

| Table aggregate | Not supported

| Server-side actions | Not supported

Misc

| Auto-ID | Not supported

| Idempotency | Not supported

### GraphQL

Read-only JSON

[GraphQL](https://graphql.org) [Vantage driver](https://docs.rs/vantage-api-client) [GraphQL queries](https://graphql.org/learn/queries/)

Generic and Hasura dialects. Read rows, filter, and drill into related records. With Hasura, sort, search and operator filters run on the server.

Retrieving data

| Filter by conditions | Supported

| Conditional operators | Partly supported (Hasura dialect only.)

| Server-side sort | Partly supported (Hasura dialect only.)

| Quick search | Partly supported (Hasura dialect only.)

| Count | Supported

| Column aggregates | Not supported

| Random-access pages | Partly supported (`limit` / `offset` are rendered when the table sets `paginate: true`, but the grid doesn't page with them yet.)

| Progressive (cursor) load | Not supported

Relations

| One-to-many relations | Supported

| Many-to-many relations | Not supported

| Relation aggregation | Not supported

| Arbitrary expressions | Not supported

| Column from related table | Not supported

| Contained record expressions | Not supported

| Relations defined in Rhai | Supported

Live updates

| Record changed | Not supported

| Record set changed | Not supported

| Table changed | Not supported

| Related record changed | Not supported

Editing data

| Add records | Not supported

| Update records | Not supported

| Delete records | Not supported

| Atomic import | Not supported

| Bulk modify | Not supported

Custom tables

| Tables from custom queries | Not supported

| Table aggregate | Not supported

| Server-side actions | Not supported

Misc

| Auto-ID | Not supported

| Idempotency | Not supported

### REST APIs

Read-only JSON

[Vantage driver](https://docs.rs/vantage-api-client)

REST endpoints as tables. Filters, sort and paging map onto the URL as configured per API, and work when the API honours them.

Retrieving data

| Filter by conditions | Partly supported (Equality only, as a URL path segment or `?field=value`; the API has to honour it. Can be set to filter in the app instead.)

| Conditional operators | Not supported

| Server-side sort | Partly supported (When the API has a sort parameter (`OrderingParams`); one column at a time.)

| Quick search | Not supported

| Count | Partly supported (Exact when the API reports a total (`total_key`); otherwise the rows are fetched and counted.)

| Column aggregates | Not supported

| Random-access pages | Partly supported (When page/limit or skip/limit parameters are configured and the API supports them.)

| Progressive (cursor) load | Not supported

Relations

| One-to-many relations | Supported

| Many-to-many relations | Not supported

| Relation aggregation | Not supported

| Arbitrary expressions | Not supported

| Column from related table | Not supported

| Contained record expressions | Not supported

| Relations defined in Rhai | Supported

Live updates

| Record changed | Not supported

| Record set changed | Not supported

| Table changed | Not supported

| Related record changed | Not supported

Editing data

| Add records | Not supported

| Update records | Not supported

| Delete records | Not supported

| Atomic import | Not supported

| Bulk modify | Not supported

Custom tables

| Tables from custom queries | Not supported

| Table aggregate | Not supported

| Server-side actions | Not supported

Misc

| Auto-ID | Not supported

| Idempotency | Not supported

### AWS

Read-only JSON

[AWS](https://aws.amazon.com) [Vantage driver](https://docs.rs/vantage-aws)

Infrastructure (CloudWatch, IAM, S3 and more) browsed as tables, with equality filters pushed down to the API.

Retrieving data

| Filter by conditions | Supported

| Conditional operators | Not supported

| Server-side sort | Not supported

| Quick search | Not supported

| Count | Supported

| Column aggregates | Not supported

| Random-access pages | Not supported

| Progressive (cursor) load | Not supported

Relations

| One-to-many relations | Supported

| Many-to-many relations | Not supported

| Relation aggregation | Not supported

| Arbitrary expressions | Not supported

| Column from related table | Not supported

| Contained record expressions | Not supported

| Relations defined in Rhai | Not supported

Live updates

| Record changed | Not supported

| Record set changed | Not supported

| Table changed | Not supported

| Related record changed | Not supported

Editing data

| Add records | Not supported

| Update records | Not supported

| Delete records | Not supported

| Atomic import | Not supported

| Bulk modify | Not supported

Custom tables

| Tables from custom queries | Not supported

| Table aggregate | Not supported

| Server-side actions | Not supported

Misc

| Auto-ID | Not supported

| Idempotency | Not supported

### CLI tools

Read-only JSON

[Vantage driver](https://docs.rs/vantage-cmd)

Wrap a command (aws, kubectl, gh…) and read the JSON it prints as rows.

Retrieving data

| Filter by conditions | Not supported

| Conditional operators | Not supported

| Server-side sort | Not supported

| Quick search | Not supported

| Count | Supported

| Column aggregates | Not supported

| Random-access pages | Not supported

| Progressive (cursor) load | Not supported

Relations

| One-to-many relations | Not supported

| Many-to-many relations | Not supported

| Relation aggregation | Not supported

| Arbitrary expressions | Not supported

| Column from related table | Not supported

| Contained record expressions | Not supported

| Relations defined in Rhai | Supported

Live updates

| Record changed | Not supported

| Record set changed | Not supported

| Table changed | Not supported

| Related record changed | Not supported

Editing data

| Add records | Not supported

| Update records | Not supported

| Delete records | Not supported

| Atomic import | Not supported

| Bulk modify | Not supported

Custom tables

| Tables from custom queries | Not supported

| Table aggregate | Not supported

| Server-side actions | Not supported

Misc

| Auto-ID | Not supported

| Idempotency | Not supported

### CSV files

Read-only Typed text

[Vantage driver](https://docs.rs/vantage-csv) [CSV format (RFC 4180)](https://www.rfc-editor.org/rfc/rfc4180)

Local files as tables, with in-memory filtering and record-level traversal.

Retrieving data

| Filter by conditions | Supported

| Conditional operators | Not supported

| Server-side sort | Not supported

| Quick search | Not supported

| Count | Supported

| Column aggregates | Not supported

| Random-access pages | Not supported

| Progressive (cursor) load | Not supported

Relations

| One-to-many relations | Supported

| Many-to-many relations | Not supported

| Relation aggregation | Not supported

| Arbitrary expressions | Not supported

| Column from related table | Not supported

| Contained record expressions | Not supported

| Relations defined in Rhai | Supported

Live updates

| Record changed | Not supported

| Record set changed | Not supported

| Table changed | Not supported

| Related record changed | Not supported

Editing data

| Add records | Not supported

| Update records | Not supported

| Delete records | Not supported

| Atomic import | Not supported

| Bulk modify | Not supported

Custom tables

| Tables from custom queries | Not supported

| Table aggregate | Not supported

| Server-side actions | Not supported

Misc

| Auto-ID | Not supported

| Idempotency | Not supported

### Append logs

Append-only JSONL

[Vantage driver](https://docs.rs/vantage-log-writer) [JSON Lines format](https://jsonlines.org)

Append-only JSONL log files — write structured entries that the log viewer picks up on its next refresh.

Retrieving data

| Filter by conditions | Not supported

| Conditional operators | Not supported

| Server-side sort | Not supported

| Quick search | Not supported

| Count | Not supported

| Column aggregates | Not supported

| Random-access pages | Not supported

| Progressive (cursor) load | Not supported

Relations

| One-to-many relations | Not supported

| Many-to-many relations | Not supported

| Relation aggregation | Not supported

| Arbitrary expressions | Not supported

| Column from related table | Not supported

| Contained record expressions | Not supported

| Relations defined in Rhai | Supported

Live updates

| Record changed | Not supported

| Record set changed | Not supported

| Table changed | Not supported

| Related record changed | Not supported

Editing data

| Add records | Supported

| Update records | Not supported

| Delete records | Not supported

| Atomic import | Not supported

| Bulk modify | Not supported

Custom tables

| Tables from custom queries | Not supported

| Table aggregate | Not supported

| Server-side actions | Not supported

Misc

| Auto-ID | Not supported

| Idempotency | Not supported

### Memory

Read / write In-process

[Vantage driver](https://docs.rs/vantage-memory)

Tables held in the app's own memory — what Faker simulations and tests run on. Every operator, sort, search, paging, atomic import and live updates, with no server.

Retrieving data

| Filter by conditions | Supported

| Conditional operators | Supported

| Server-side sort | Supported

| Quick search | Supported

| Count | Supported

| Column aggregates | Supported

| Random-access pages | Supported

| Progressive (cursor) load | Not supported

Relations

| One-to-many relations | Supported

| Many-to-many relations | Partly supported (Matches with in against the related ids, fetched first — not as a subquery.)

| Relation aggregation | Not supported

| Arbitrary expressions | Not supported

| Column from related table | Not supported

| Contained record expressions | Not supported

| Relations defined in Rhai | Supported

Live updates

| Record changed | Supported

| Record set changed | Supported

| Table changed | Supported

| Related record changed | Not supported

Editing data

| Add records | Supported

| Update records | Supported

| Delete records | Supported

| Atomic import | Supported

| Bulk modify | Not supported

Custom tables

| Tables from custom queries | Not supported

| Table aggregate | Not supported

| Server-side actions | Not supported

Misc

| Auto-ID | Supported

| Idempotency | Supported

What stands out

- Faker simulations write into it on a schedule, so grids, charts and logs have moving data to show.
- Live updates are scoped to the vista's query: a row that stops matching arrives as a delete.
- No server, no files — the data lasts as long as the app runs.

Every GUI element adapts to the table it's bound to — buttons and features follow the backend's capabilities.

## Build a rich GUI — not just CRUD

In Vantage, UI elements are reactive. YAML controls layout and visibility, while Rhai drives behaviour. The data grid is a typical example — YAML sets column order, types, widths and captions, plus the buttons above the grid; Rhai scripts what a button press does.

### Data grids

- Virtualized — stays smooth past a million rows.
- Persistent sort, quick search and column resize, per project.
- Background refresh with no flicker, on change or a schedule.

### Tabs & drill-downs

- Open related records in child tabs; pin the ones you keep.
- Chain multi-hop drill-downs from a row's context menu.

### Forms, dialogs & actions

- Add and edit records in form dialogs; confirm destructive steps.
- Right-click actions run operations or call your own services.
- Status workflows offer only the valid next transitions.

### Wizards

- Multi-step flows for guided data entry and operations.
- Collect input across screens, then commit in one go.
- Fully scripted interactions — full access to all tables.
- A reactive UI to display progress bars or logs.

### Charts & dashboards

- Stacked bars, lines, pies and KPI cards on one dashboard grid.
- Filter dropdowns narrow the query itself, so every figure recomputes.
- Deltas colour by meaning — a rising cost reads red, not green.

### Custom UI elements

- Reactively bind to tables.
- Kanban, maps and many other custom UI widgets.
- Allow scripting and custom actions.

## Vantage for the Enterprise

As an enterprise client, you get a custom release pipeline with your own configuration of Vantage. Supply your own DataSources, add table definitions in **native Rust**, and bundle your own actions.

| Capability | Free download One binary, everyone | Enterprise build Assembled for you

| Build your app

| Datasources out of the box | 12 | 12 + your own

| Colour themes | 36 | 36 + one that's yours

| Native types mapped per source | up to 24 | + types you define

| Grids past a million rows | Included | Included

| Charts, KPI cards, dashboards | Included | Included

| Multi-step wizards & CSV import | Included | Included

| Custom form layouts | Included | Included

| Auto-refresh in the background | Included | Included

| Push-style instant refresh | SurrealDB, MongoDB | + CDC: Kafka, Debezium, custom listeners

| Your AI agent builds it over MCP | Included | Included

| MCP debugging — query preview, error check | Included | + BDD suite, run at build

| Custom tables

| Custom queries & aggregates | Rhai | Rhai + Rust

| Actions | Rhai | Rhai + Rust

| Internal API | Rhai | Rhai + Rust

| [Custom datasources](https://vantage-ui.com/book/new-persistence.html) | [OSS, community](https://github.com/romaninsh/vantage) | yours or ours

| UI widgets | 21 built in | + your own in Rust

| Third-party WASM plugins | Not included | Included

| Internal distribution control

| Application distribution | vantage-ui.com, or clone by hand | internal catalog, apps auto-update

| Platforms | macOS, Linux | + API/MCP

| Verifiable builds, on demand | Not included | your components in the binary

| Your name, icon and About box | Not included | Included

| Turn off what you don't need | Not included | Included

| Your own release channel | Not included | signed & notarised

| vantage:// install allowlist | Not included | your apps only

| Central credentials & SSO sign-in | Not included | Included

| Crash telemetry | optional | your own Sentry account

| What you're standing on

| MIT framework underneath | forever | forever

| Architecture partner & training | Not included | Included

| Support | community | [Slack Connect](https://slack.com/intl/en-gb/blog/collaboration/slack-shared-channels)

| Price for personal and commercial use | $0 forever | [talk to us](https://vantage-ui.com/solutions/enterprise/#ent-form)

## On the roadmap

Where Vantage is heading. Everything we ship reaches every build — free and enterprise alike. Tap the deck to flip through.

Roadmap

### Windows

macOS and Linux today. A signed Windows build brings the same app to the laptops most of your colleagues actually use — no VM, no remote desktop.

Roadmap

### The web

The same YAML and Rhai, rendered in a browser. Hand someone a link instead of an install, and put a screen in front of people who will never open a terminal.

Roadmap

### Server-side facade APIs

Turn the same config — data sources plus Rhai logic — into real backend APIs your own frontend or mobile app can call. Start in the app; graduate to code.

Roadmap

### Export to real code

No lock-in: export your app to a code repository or container image you own and run anywhere. Start in low-code, leave with real code.

Click to deal the next card

[Download for Mac — free](https://vantage-ui.com/download/) [See example apps](https://vantage-ui.com/examples/)
