Built-in Functions Reference
Complete reference for built-in functions available in TinySystems expressions.
Source of truth: ajson/math.go (expression engine, github.com/tiny-systems/ajson v0.1.6) and pkg/evaluator/functions.go (SDK additions).
Function names are case-insensitive (RFC3339(...) and rfc3339(...) are the same function). There is no int() and no len() — use length() or size() for lengths. JavaScript-style property access like $.items.length is not supported; use length($.items).
Time Functions
now()
Returns the current Unix timestamp in seconds.
Returns: number (seconds since Unix epoch)
{{now()}}
// 1705312200
RFC3339()
Formats a Unix timestamp (seconds) as an RFC3339 string. With a non-numeric argument it formats the current time.
{{RFC3339(now())}}
// "2024-01-15T10:30:00Z"
{{RFC3339($.createdAtSeconds)}}
// "2024-01-10T14:22:35Z"
Time and duration arithmetic with + and -
The SDK overrides + and - for strings so RFC3339 times and Go duration strings combine:
{{RFC3339(now()) + "1h"}} // one hour from now (RFC3339 string)
{{"2h" - "30m"}} // "5400s" (durations combine to seconds)
{{RFC3339(now()) - "24h"}} // yesterday
Type Conversion
string()
Converts a value to string.
| Input | Output |
|---|---|
42 | "42" |
3.14 | "3.14" |
true / false | "true" / "false" |
| object | its JSON representation |
| string | unchanged |
null, array | "unknown" |
{{string($.count)}}
// 42 -> "42"
{{'ID-' + string($.id)}}
// "ID-123"
There is no int(), float() or number() function. To force numeric context, use arithmetic on already-numeric data, or round()/floor()/trunc() for rounding.
Length and Size
length()
Array length or string byte length; 1 for other values, 0 when the argument is missing (e.g. a path that resolved to nothing).
{{length($.items)}} // [1,2,3] -> 3
{{length($.name)}} // "Alice" -> 5
{{length($.text) > 0}}
size()
Container size: array element count, object key count, string byte length.
{{size($.items)}}
{{size($.userMap)}}
String Functions
Single-argument (error if the argument is not a string):
| Function | Description | Example |
|---|---|---|
upper(s) | Uppercase | {{upper($.name)}} → "ALICE" |
lower(s) | Lowercase | {{lower($.email)}} |
trim(s) | Strip surrounding whitespace | {{trim($.input)}} |
reverse(s) | Reverse characters (rune-aware) | {{reverse('abc')}} → "cba" |
Multi-argument:
| Function | Signature | Description |
|---|---|---|
split | split(string, separator) → array | Split a string |
join | join(array, separator) → string | Join an array of strings |
contains | contains(string, substring) → bool | Substring test |
hasprefix | hasprefix(string, prefix) → bool | Prefix test |
hassuffix | hassuffix(string, suffix) → bool | Suffix test |
replace | replace(string, old, new) → string | Replace all occurrences |
substr | substr(string, start[, length]) → string | Substring; negative start counts from the end |
index | index(string, substring) → number | First occurrence index, -1 if absent |
{{join(split($.csv, ','), ';')}}
{{contains($.email, '@example.com')}}
{{substr($.id, 0, 8)}}
{{replace($.path, '/', '-')}}
For regex matching use the =~ operator: {{$.email =~ '^[^@]+@[^@]+$'}}.
Base64
| Function | Description |
|---|---|
b64encode(s) | Standard base64 with padding |
b64encoden(s) | Standard base64 without padding |
b64decode(s) | Decode (accepts padded and unpadded input) |
Non-string input returns null.
{{b64encode($.payload)}}
{{b64decode($.encoded)}}
Aggregates
sum()
Sum of a numeric array (errors if any element is non-numeric). A bare number passes through; empty array → 0; non-numeric scalar → null.
{{sum($.prices)}}
avg()
Average of a numeric array. Empty array → 0; bare number passes through.
{{avg($.scores)}}
first() / last()
First/last element of an array; null for empty arrays or non-arrays.
{{first($.items)}}
{{last($.items)}}
Logic
not()
Boolean negation with truthiness coercion (there is no unary ! operator).
{{not($.disabled)}}
{{not($.a > $.b)}}
Truthiness: false, 0, "", null, empty array, empty object → false; everything else → true.
Node Navigation
| Function | Description |
|---|---|
parent(n) | Parent node of a path result (null at root) |
root(n) | Root of the document the node belongs to |
key(n) | Object key under which the node is stored (null if parent is not an object) |
{{key($.items.first)}}
{{parent($.deeply.nested.value)}}
Random
| Function | Description |
|---|---|
rand(n) | Random float in [0, n) |
randint(n) | Random integer in [0, n) |
{{randint(100)}}
{{rand(1)}}
Math Functions
All operate on numbers and error on non-numeric input.
| Function | Description |
|---|---|
abs(n) | Absolute value |
ceil(n) | Round up |
floor(n) | Round down |
round(n) | Round half away from zero |
roundtoeven(n) | Round half to even |
trunc(n) | Truncate toward zero |
sqrt(n), cbrt(n) | Square/cube root |
exp(n), exp2(n), expm1(n) | Exponentials |
log(n), log2(n), log10(n), log1p(n), logb(n) | Logarithms |
pow10(n) | 10ⁿ (integer n) |
factorial(n) | n! (non-negative integer) |
sin, cos, tan, asin, acos, atan | Trigonometry |
sinh, cosh, tanh, asinh, acosh, atanh | Hyperbolic |
gamma, erf, erfc, erfinv, erfcinv, j0, j1, y0, y1 | Special functions |
For exponentiation with an arbitrary base use the ** operator: {{2 ** 10}} → 1024.
{{round($.price * 100) / 100}} // round to 2 decimal places
{{abs($.a - $.b)}}
Constants
| Constant | Value |
|---|---|
e | 2.71828… |
pi | 3.14159… |
phi | 1.61803… |
sqrt2, sqrte, sqrtpi, sqrtphi | Square roots of 2, e, π, φ |
ln2, ln10, log2e, log10e | Log constants |
true, false, null | Literals |
{{2 * pi * $.radius}}
Function Quick Reference
| Function | Returns | Description |
|---|---|---|
now() | number | Current Unix timestamp (seconds) |
RFC3339(ts) | string | Format seconds timestamp as RFC3339 |
string(v) | string | Convert to string (null/array → "unknown") |
length(v) | number | Array/string length |
size(v) | number | Container size |
upper/lower/trim/reverse(s) | string | String transforms |
split(s, sep) | array | Split string |
join(a, sep) | string | Join array |
contains/hasprefix/hassuffix(s, x) | bool | String tests |
replace(s, old, new) | string | Replace all |
substr(s, start[, len]) | string | Substring |
index(s, sub) | number | Find substring |
b64encode/b64encoden/b64decode(s) | string | Base64 |
sum(a) / avg(a) | number | Aggregates |
first(a) / last(a) | any | Array ends |
not(v) | bool | Negation (no ! operator) |
parent/root/key(n) | node | Navigation |
rand(n) / randint(n) | number | Random |
factorial(n), pow10(n) | number | Math |
abs, ceil, floor, round, trunc, sqrt, log*, exp*, trig | number | Go math set |
Usage Examples
Timestamp Formatting
created: "{{RFC3339(now())}}"
# "2024-01-15T10:30:00Z"
Data Normalization
email: "{{lower(trim($.email))}}"
# " USER@EXAMPLE.COM " -> "user@example.com"
Calculations
discountedPrice: "{{round(($.price * 0.9) * 100) / 100}}"
Conditionals with Functions
hasContent: "{{length($.text) > 0}}"
displayName: "{{length($.nickname) > 0 ? $.nickname : $.fullName}}"
Combined Operations
summary: "{{upper($.name)}} - Items: {{length($.items)}} - Total: ${{round($.total)}}"
# "ALICE - Items: 5 - Total: $150"
Error Handling
- A whole-string expression (
"{{expr}}") that fails evaluates tonull; the error is reported to the flow's expression error log. - A failed expression inside an interpolated string is left unevaluated (the literal
{{expr}}stays visible) so you can see what failed. - Passing the wrong type to a function is an error (e.g.
upper(5)), not a coercion. ||does not provide default values — it always returns a boolean. Use the ternary instead:
# Correct default value
name: "{{length($.name) > 0 ? $.name : 'unknown'}}"
# Wrong — always true/false, never the string
name: "{{$.name || 'unknown'}}"