Script Fields
A Script field is a virtual column whose value is the return value of a short PHPScript snippet. Like a Calculation field it stores nothing and can't be edited — but instead of a SQL formula it runs real code, so it can query related records, call string and date functions, and build formatted output.
Use a script field when a Calculation can't express what you need: multi-step logic, a lookup that a token can't reach, or a small piece of HTML.
Adding a script field
In a table's Configure screen, open the Fields tab, click Add Field, and choose Script. Give it a label, then write the snippet in the code editor. Pick a Render mode (Text or HTML) and save.
The snippet must return a single value, which is cast to a string and shown in the cell. Returning nothing — or a non-scalar like an array — shows an empty cell.
return "Hi " . $record["first_name"];
When it runs
A script field is evaluated lazily, once per record, when you open the record detail screen — not in grids, lists, or API query results (there it shows blank). Each field runs on its own, so one slow or failing field never blocks the others, and a throwing snippet renders an inline error in just that cell without failing the record.
Each evaluation is capped at 5 seconds. Keep queries cheap.
What the snippet can use
| Variable | What it holds |
|---|---|
$record |
This record's values, keyed by field id (the SQL column) — e.g. $record["email"], $record["amount"]. Plus $record["_meta"]["id"] and $record["_meta"]["title"]. |
$user |
The viewing user (id, email, name), or null when unauthenticated (e.g. a public API resolve). |
You can read the workspace with the same query helpers as a flow — records_query(), records_query_one(), record_get(), records_count() — scoped to this table's workspace.
A script field only displays a value — it must never change data. Do not call record_create(), record_update(), record_delete(), record_email_send(), or record_comment(): the snippet runs every time anyone opens the record, so a side effect there would fire again and again. Anything that writes, sends, or has a side effect belongs in an automation.
Render modes
- Text (default) — the return value is escaped and shown as-is, whitespace preserved. Don't hand-escape; it's automatic.
- HTML — the return value is rendered as HTML in a sandboxed frame. Styles, SVG, and tables are fine; JavaScript does not run. Only return HTML when the field is set to HTML render.
Examples
Derived label (text):
return strtoupper($record["status"]);
Roll up a related total with a read query (text):
$lines = records_query("invoice_lines", ["invoice" => $record["_meta"]["id"]]);
$sum = 0;
foreach ( $lines as $l ) { $sum += floatval($l["amount"]); }
return number_format($sum, 2);
A small status badge (HTML render — no JavaScript):
$overdue = $record["due_date"] && strtotime($record["due_date"]) < time();
return $overdue
? "<span style='color:#b00;font-weight:bold'>Overdue</span>"
: "<span style='color:#080'>On track</span>";
Script field vs calculation vs automation
| You want | Use |
|---|---|
| A live derived value from a SQL formula | Calculation field |
| A live derived value that needs code, a query, or HTML | Script field |
| To freeze a value at create/update time | Automation writing a regular field |
| To send mail, call an API, or change another record | Automation |
| To block a bad write before it saves | Validation rule |
Reach for a calculation first — it's cheaper and always current. Move up to a script field when the value genuinely needs logic a formula can't express.