Skip to main content

Computed Fields

Computed fields are read-only fields whose values are calculated automatically from other fields in the same row. Define a formula in the schema — the platform computes and stores the result on every write.

Computed fields are not ephemeral — they are persisted in the database like regular fields. You can filter, sort, and query by them in APIs just like any other field.

Basic Computed Fields

Add x-formula and readOnly: true to any string, number, or boolean field. Example: a products table with computed total, inStock, and label:

{
"title": "iPhone 16 Pro",
"price": 999,
"quantity": 50,
"total": 49950,
"inStock": true,
"label": "iPhone 16 Pro — $999"
}

total, inStock, label are computed automatically — you only write title, price, quantity.

Schema Editor — formula expression editor for total field (price * quantity)
Schema Editor — formula expression editor for total field (price * quantity)
Row Editor — MacBook M4 with computed label, total, inStock showing formula icons
Row Editor — MacBook M4 with computed label, total, inStock showing formula icons

Array Formulas

Formulas inside array items can compute per-item values, reference root-level fields, use position context, and aggregate across all items.

Example: an order with line items — each item computes subtotal and discounted price, the root computes totals:

{
"customer": "Acme Corp",
"discount": 0.1,
"items": [
{ "name": "iPhone 16 Pro", "qty": 10, "unitPrice": 999,
"subtotal": 9990, "discountedPrice": 899.1, "position": 1 },
{ "name": "MacBook M4", "qty": 5, "unitPrice": 1999,
"subtotal": 9995, "discountedPrice": 1799.1, "position": 2 },
{ "name": "AirPods Pro", "qty": 20, "unitPrice": 249,
"subtotal": 4980, "discountedPrice": 224.1, "position": 3 }
],
"totalAmount": 24965,
"itemCount": 3,
"avgPrice": 1082.33
}
Table Editor — orders with computed avgPrice, itemCount, totalAmount columns
Table Editor — orders with computed avgPrice, itemCount, totalAmount columns
Row Editor — order with items showing computed position, subtotal, discountedPrice per item and aggregated totals
Row Editor — order with items showing computed position, subtotal, discountedPrice per item and aggregated totals

What's happening

FormulaLocationWhat it does
qty * unitPriceArray itemSubtotal per line item
unitPrice * (1 - /discount)Array itemUses root /discount for discounted price
#index + 1Array item1-based position via context token
sum(items[*].subtotal)RootSum all subtotals using wildcard [*]
count(items)RootNumber of items in array
avg(items[*].unitPrice)RootAverage unit price across all items

Context Tokens

Available inside array item formulas:

TokenTypeDescription
#indexnumberCurrent array index (0-based)
#lengthnumberArray length
#firstbooleantrue if first element
#lastbooleantrue if last element
@prevobjectPrevious element (null if first)
@nextobjectNext element (null if last)
#parent.indexnumberIndex in parent array (nested arrays)
#root.indexnumberIndex in topmost array

Practical Patterns

Running total (like Excel):

if(#first, subtotal, @prev.runningTotal + subtotal)

Nested numbering (sections[].questions[] → "1.1", "1.2", "2.1"):

concat(#parent.index + 1, ".", #index + 1)

Delta from previous:

if(#first, 0, value - @prev.value)

Field References

Simple — top-level fields

price * quantity

Nested paths — dot notation

stats.damage * multiplier
user.profile.name

Array index — specific element

items[0].price           // first
items[-1].name // last

Array wildcard [*] — all elements

sum(items[*].subtotal)
avg(ratings[*].score)
orders[*].items[*].amount // flatten nested arrays

Root path / — absolute reference from root

Always resolves from the top level, even inside array item formulas:

price * (1 + /taxRate)
unitPrice * /config.multiplier

Relative path ../ — go up one level

../discount                  // parent level
../../rootRate // two levels up
../config.multiplier // parent's nested field

Bracket notation — field names with hyphens

["field-name"]               // without brackets: field - name = subtraction!
obj["field-name"].value

Schema Rules

  1. Computed fields must have "readOnly": true
  2. Computed fields must have a "default" value
  3. Computed fields must be in the "required" array
  4. Expressions reference fields in the same row only
  5. Circular dependencies are not allowed
  6. foreignKey and x-formula cannot coexist on the same field

Limitations

  • Formulas reference fields within the same row only. Cross-table computed fields are not supported.
  • Computed fields are read-only — you cannot write to them directly.

Full specification: Formula SPEC.md


Reference: Operators

Arithmetic

OperatorDescriptionExample
+Addition / string concatenationprice + tax, first + " " + last
-Subtractionprice - discount
*Multiplicationprice * quantity
/Divisiontotal / count
%Moduloindex % 2

Comparison

OperatorExample
== !=status == "active", role != "guest"
> < >= <=quantity > 0, price <= 1000

Logical

OperatorExample
&&quantity > 0 && price < 1000
||role == "admin" || role == "editor"
!!isArchived

Reference: Built-in Functions

String

FunctionSignature
concatconcat(value1, value2, ...) → string
upper / lowerupper(text) → string
trimtrim(text) → string
left / rightleft(text, count) → string
replacereplace(text, search, replacement) → string
joinjoin(array, separator?) → string
lengthlength(value) → number

Numeric

FunctionSignature
roundround(number, decimals?) → number
floor / ceilfloor(number) → number
absabs(number) → number
sqrtsqrt(number) → number
powpow(base, exponent) → number
min / maxmin(value1, value2, ...) → number
log / log10 / explog(number) → number
signsign(number) → number

Boolean

FunctionSignature
containscontains(text, search) → boolean
startswith / endswithstartswith(text, prefix) → boolean
includesincludes(array, value) → boolean
isnullisnull(value) → boolean
and / or / notand(a, b) → boolean

Array

FunctionSignature
sumsum(array) → number
avgavg(array) → number
countcount(array) → number
first / lastfirst(array) → any

Conditional

FunctionSignature
ifif(condition, valueIfTrue, valueIfFalse) → any
coalescecoalesce(value1, value2, ...) → any

Conversion

FunctionSignature
tostringtostring(value) → string
tonumbertonumber(value) → number
tobooleantoboolean(value) → boolean