Linked Records, Lookup & Rollup
Connect tables to each other, show values from connected records, and calculate totals across them — like "each Customer's Orders" and "the sum of those orders".
Three field types work together: a Link connects rows in one table to rows in another; a Lookup shows a field from the connected rows; a Rollup turns those values into one number or text (sum, count, average…).
All of it is calculated by the database itself, straight from the live data — values are always current, and open grids update in real time when connected records change.
On this page
Link Fields — Connecting Tables
A Link field connects rows across two tables — a Customer to their Orders, a Project to its Tasks, a Student to their Courses. Linked rows show up as clickable chips in the grid.
- In the Base Editor, click + to add a column and choose Link to another table
- Pick which table it should connect to and the relationship type (one-to-many, many-to-many…)
- By default a reciprocal field is created in the other table too — link an Order to a Customer and the Customer automatically shows that Order
- Click the + chip in any cell to pick records to connect — the picker shows each record's name
A table can even link to itself — for example an Employees table where each manager links to their reports.
Lookup Fields
A Lookup shows a field from the connected records without copying it. Example: on each Customer, show the titles of their linked Orders.
When you create one you pick: which link to follow, which field to show from the other table, and how to show it:
| Display choice | What you see |
|---|---|
| Show all values | Comma-separated list — "Alpha, Beta" |
| First / Last value | Just one value, following the link order |
| List of values | The values as a list |
| Count / Sum / Average / Min / Max | A quick calculation over the values |
Rollup Fields
A Rollup reduces the connected records to a single answer. Example: each Customer's Total = the sum of their Orders' amounts.
| Calculation | Meaning | With no linked records |
|---|---|---|
| Count linked records | How many records are connected | 0 |
| Count non-empty / empty / unique | Counts over the chosen field's values | 0 |
| Sum | Adds the numbers up | 0 |
| Average / Median | Typical value of the numbers | blank |
| Minimum / Maximum | Smallest / largest number | blank |
| Join values | Comma-separated text of the values | blank |
| List of values / unique values | The values as a list | blank |
Empty cells and blank text are ignored by number calculations — a task with no Points doesn't drag the Average down.
Conditions & Chains
Only include records where… — both lookups and rollups can take an optional condition, so only the connected records that match are counted. Example: a Customer's "Outreach Limit" = sum of linked Sending Accounts' Daily Limit, only where Purpose is Outreach. Set it right in the Add Column dialog.
Chains — a lookup or rollup can read a field that is itself computed on the other table. Example: each Company has a rollup of its Cities' population; a Region can then sum its Companies' rollups. Chains resolve fresh from the live data (up to 3 computed hops), and a chain that would loop back on itself is rejected when you try to save it.
Always Up To Date
Lookup and rollup values are calculated by the database from the live data every time they are read — there is no cached copy that can go stale. If someone edits, links, unlinks, or deletes a connected record, every affected value is correct on the very next read, and grids that are already open update in real time, even across tables.
Example: your Customers grid is open showing Acme's Total of $150. A teammate edits one of Acme's orders from $100 to $200 in the Orders table. Acme's Total changes to $250 on your screen without a refresh.
Rules & Behavior
- Read-only: lookup and rollup cells can't be typed into — their value always comes from the connected records. Writes that include them are accepted and the computed keys are simply ignored, so integrations that read a row and send it back never break.
- Filterable: view filters work on lookup/rollup values ("Total greater than 100", "Statuses contains blocked") and run in the database for speed. List-style values filter more slowly on large tables.
- Link order matters: "First value" and joined text follow the order of the chips — drag to reorder links and the values follow.
- Deleting records: deleting a connected record removes it from every calculation automatically.
In the SDK & Backend Functions
Computed values are included in every row you read — no extra calls:
// Lookup/rollup values arrive with the row, already calculated
const { rows } = await ctx.tables.getRows('Customers', { limit: 50 });
rows[0].data['Total']; // e.g. 250 — the rollup value
rows[0].data['Order Titles']; // e.g. "Alpha, Beta"
// Writing them back is harmless — computed keys are ignored
await ctx.tables.updateRow('Customers', rowId, rows[0].data);Filtering by computed fields is supported in view filters (the grid). The filterRows API can't filter by lookup/rollup values — for computed-field conditions in code, use raw SQL via ctx.tables.query in a backend function ("Total" and friends are real queryable columns there).
Linked records themselves are managed with the linked-records API (link, unlink, reorder) — see the backend functions reference.