In the previous deep dive I left a question mark between Cart and Item. I promised that a relation is easy to change later. Before we get to how relations are declared, I want to talk about the idea underneath them, because it is the reason Vantage looks the way it does.
In Vantage you work with Sets of Records most of the time.
How simple code gets lost๐
A client runs a web shop and wants an admin dashboard that shows the total amount sitting in all open carts. Most software reaches the database through a database abstraction layer, and in practice that means picking one of two teams:
Admin dashboard: total amount across all open carts.
Team ORM
total = 0
for cart in Cart.filter(status="open"):
for line in cart.items:
total += line.amount4 lines · loads every cart
Team SQL
SELECT SUM(i.amount)
FROM cart c
JOIN cart_item i ON i.cart_id = c.id
WHERE c.status = 'open'4 lines · knows the schema
Keep the dashboard live. Next quarter, carts move to MongoDB.
Both teams: rewrite
- cart service
- outbox
- Kafka
- consumer
- projection
- read model
- WebSocket
plus idempotency keys, retries, replays and projection rebuilds
months of work for a team · TCOTCO Total cost of ownership: everything a system costs over its whole life, not just to build it, including running, maintaining, staffing and changing it.Read the docs โ for life
I gave this requirement to AI agents. Each got the first ticket and chose a team: half wrote the SQL, half used their ORM. When I added that the code mustn't depend on the database, the agent wrote the loop. Then I added the second ticket, and every agent gave the same answer: the pipeline above, plus a view that runs behind the data. Their sketches fit on a page. Building and running each box takes a team months, which is why companies at this stage employ hundreds of engineers.
That is how most apps grow. You start with SQL or an ORM. When you have to scale, you rewrite and bring in a wide range of tools. Along the way the simple, readable code is lost in implementation detail, and the core of the app becomes hard to maintain.
Define it now, don't rewrite later๐
Vantage takes the other road. Business code doesn't assume SQL and doesn't fetch records: it describes sets of records and traverses from set to set. SQL works in sets too, but SQL is implementation: it names tables, joins and an engine. A set is business code: it says which records you mean. In Vantage a data set is a VistaVista A universal handle on one table from any data source. It knows the columns, their types and what the source can do, so a generic grid or form can work with it without knowing your database.Read the blog post โRead the docs โ, the primitive from the previous deep dive, detached from how and where the data is stored. The code stays easy to read, and Vantage handles the implementation details, which you can still customise where you need to.
Admin dashboard: total amount across all open carts.
What you write
# table/cart.yaml
# Defines the Vista (a data set): columns, conditions and references.
datasource: shop_pg
columns:
id: { type: string, flags: [id] }
user: { type: string, references: user }
status: { type: string, enum: [open, ordered] }
references:
items: { table: cart_item, kind: has_many, foreign_key: cart }let report_vista = table("cart")
.where("status", "open").ref("items");Each step returns a new VistaVista A universal handle on one table from any data source. It knows the columns, their types and what the source can do, so a generic grid or form can work with it without knowing your database.Read the blog post โRead the docs โ. Bind report_vista to a widget, and the widget totals the amount.
You get, without writing it:
- WebSocket API
- live updates
- REST and MCP
- typed TypeScript client
- sessions and scope
- ACL and policies
a dozen lines of YAML and Rhai
Keep the dashboard live. Next quarter, carts move to MongoDB.
What you change
# table/cart.yaml
- datasource: shop_pg
+ datasource: shop_mongoone line · business code unchanged
Live updates are among those details. Each data source reports its own changes: PostgreSQL through LISTEN/NOTIFY, MongoDB through change streams, and SurrealDB through LIVE SELECT, which can even push the totals of a pre-computed view as the rows under it change. Vantage turns them into updates over its WebSocket API. The event pipeline from the first story still exists, but it is part of Vantage: it runs inside Vantage Server, and nobody on your team has to manage it. The Enterprise edition goes a step further and plugs into the event architecture a company already runs, such as CDC with Debezium, scaling horizontally with it.
Moving the data to MongoDB takes one line because traversal doesn't depend on the database: each ref() turns one VistaVista A universal handle on one table from any data source. It knows the columns, their types and what the source can do, so a generic grid or form can work with it without knowing your database.Read the blog post โRead the docs โ into the next, whether or not both tables share a database.
If you prefer to write Rust, Vantage offers all the base components as MIT-licensed open source: Vista, Factory, Diorama and Scenery. They are what Vantage ServerVantage Server Serves the same YAML and Rhai project as an API, with live WebSocket updates, REST, MCP, sessions and access rules, for web apps and other clients. and Vantage UIVantage UI The desktop app builder: you and your LLM describe tables, pages and actions in YAML and Rhai, and it turns them into a working app.Read the docs โ run on.
Conclusion๐
Follow the same app through four requirements. Each colour is code written at a different time, so a new colour means the code before it was rewritten.
~10×faster to build an app than with an LLM alone, in our tests
1 lineto move a table to another database
0rewrites of business code across all four
Vantage pursues an architectural goal: keep business code apart from implementation. Business code works with VistasVista A universal handle on one table from any data source. It knows the columns, their types and what the source can do, so a generic grid or form can work with it without knowing your database.Read the blog post โRead the docs โ: which records you mean and how they relate. Storage, queries, live updates and scaling are implementation, and Vantage implements them once, beneath every table. That is where the speed comes from, and it is why the business code doesn't need replacing as the system grows.
Most of the cost of a business system comes after the first version. In companies where hundreds of engineers maintain a shared codebase, it is the rewrites and the infrastructure that follow every new requirement. Code written for Vantage is long-term code: it scales with the system instead of being replaced by it.