Expressions

The one small formula language a document uses for anything computed or conditional — and the two ways to name a property inside it.


Wherever a document needs to work something out or decide something, it uses an expression — one line of formula, no statements, no side effects:

{ "when": "values.mood >= 8" }

It is the same language everywhere: a formula field, a dynamic default value, a rule on a card, a condition on an automation, a filter, the statistics behind a chart. Learn it once.

Two ways to name a property

Both forms resolve to exactly the same thing, so pick by what the name looks like.

values.<key> — the short form. key is the property's binding key: the stable, lowercase name it carries in the document (letters, digits and _, nothing else). This is the form to reach for inside a JSON document, because that is where you already have the binding key in front of you.

values.mood >= 8
values.reps * values.sets

prop("Name") — the call form. This one takes the property's display name, spelled exactly as it reads in the app, in double quotes.

prop("Mood score") >= 8
prop("Weight kg") / 2

Use the call form whenever the name is not a plain lowercase identifier — anything with spaces, punctuation, capitals or emoji. values.Mood score is not valid and cannot be: the dot form has no way to know where the name ends. If you get it wrong the error message hands you the working replacement rather than just complaining.

The call form is also what you will see when the app writes an expression for you, and what keeps working when you rename a property — the reference is to the property itself, not to the letters of its name.

Where the conditionality lives

Command handlers are deliberately flat: a list of things to do, with no if inside it. All the branching happens in expressions instead —

  • Card ruleswhen decides whether an element shows, or which style it takes.
  • Automation conditions — the same when, deciding whether a rule fires at all.
  • Formula fields — the whole value is an expression.
  • Default values — a new entry can start with a computed value rather than a fixed one.
  • Chart measures and filters — the same syntax over a whole column of history.

Keeping decisions in expressions and actions in commands is what makes both halves readable on their own.

Operators, functions and gaps

Arithmetic (+ - * / %), comparison (== != < <= > >=) and logic (and / or / not) all work as you would expect. There are dozens of functions on top — rounding, text, dates, durations, and a full set of statistics for chart-scope work.

Two behaviours are worth knowing before you write anything: a blank value is skipped, never counted as a zero, and a calculation with nothing to work on comes back empty rather than failing.

The full function list, generated from the engine itself, is on Function reference. The longer explanation of scope, value types and worked examples is The expression language.

Next