Transform data between steps
Data rarely arrives in the shape the next step wants. A date is in the wrong format, a list needs filtering, or a field has the wrong name. This guide shows four ways to reshape data, from the lightest to the most flexible, with an example for each.
Choose a tool
| You want to… | Use |
|---|---|
| Change one value on its way into a field: upper-case it, count a list, add up prices | An expression in the field itself |
| Do a common conversion without writing code: format a date, parse JSON, map a code to a label | A Formatter step |
| Keep only the items of a list that match conditions | A Filter step |
| Anything else: reshape objects, combine several steps' data, custom logic | A Code step |
Start with the lightest option that does the job. A field expression adds no step to the canvas, and a Formatter step is easier for someone else to read than code.
The examples on this page use an earlier HTTP step, Get orders, whose output body is:
{
"orders": [
{ "id": "A-1", "customer": "Aiko Tanaka", "total": 4200, "status": "paid", "created_at": "2026-10-26T01:30:00Z" },
{ "id": "A-2", "customer": "Ken Sato", "total": 900, "status": "refunded", "created_at": "2026-10-26T03:10:00Z" }
]
}Expressions
When a field's whole value starts with a function, AI Studio evaluates it as an expression. Expressions use JSONata, so you can do a lot in one line:
| Goal | Field value | Result |
|---|---|---|
| Count the orders | $count($.<Get orders>.output.body.orders) | 2 |
| Add up the totals | $sum($.<Get orders>.output.body.orders.total) | 5100 |
| List the customer names | $join($.<Get orders>.output.body.orders.customer, ", ") | Aiko Tanaka, Ken Sato |
| Keep only paid orders | $filter($.<Get orders>.output.body.orders, function($v) { $v.status = "paid" }) | The first order |
| Rename fields | $map($.<Get orders>.output.body.orders, function($v) { {"orderId": $v.id, "amount": $v.total} }) | [{"orderId": "A-1", "amount": 4200}, …] |
| Today's date in Japan time | $now("[Y0001]-[M01]-[D01]", "+0900") | 2026-10-27 |
Replace <Get orders> with the step's ID. Pick it from the $ list or use the copy button next to the step.
Two rules catch people out:
- The function must be the whole field. In
Total: $sum(...)the function stays as text. To mix an expression with text, build the text inside a function:$join(["Total: ", $string($sum(...))]). - The result keeps its type.
$filter(...)gives a list, so it can go straight into a Loop's Value.
The Functions tab of the data picker lists the common functions. See Expressions for all of them.
Formatter
The Formatter node does common conversions with settings instead of code. Click Add Step, open Built-in, choose Formatter, and pick an action. Some useful ones:
| Action | Example |
|---|---|
| DateTime Format | 2026-10-26T01:30:00Z to 2026/10/26 10:30:00: set To Format to Japanese DateTime and To Timezone to Asia/Tokyo. The result is formatted_date. |
| DateTime Add | A due date 14 days after an order. |
| Number Currency Format | 4200 to ¥4,200. |
| Text Parse JSON | Turn JSON that arrived as text, for example from an LLM or a form field, into an object later steps can go into. The result is result. |
| Lookup Table | Map codes to labels: with Table {"paid": "Paid", "refunded": "Refunded"} and Key the order's status, value is the label. Set Default for unknown codes. |
| Text Split / Text Join | Turn "a, b, c" into a list, or back. |
| HTML to Markdown / Text Remove HTML | Clean up email or web content before sending it to an LLM. |
Each action works on one value. To format every item of a list, put the Formatter inside a Loop, or use an expression or Code instead.
The Formatter reference lists all 27 actions.
Filter
The Filter node keeps the items of a list that match your conditions:
- Click Add Step, open Built-in, choose Filter.
- Input Data: a reference to the list, alone in the field, such as
$.<Get orders>.output.body.orders. - Filter Conditions: add conditions on the items' fields, such as
statusequalspaid. Conditions in a group must all match (AND), and groups are alternatives (OR), as in a Path. - Decide what happens when nothing matches. By default the run stops. Turn on Continue on Empty Results to carry on with an empty list.
The matching items are in the step's filtered output.
Code
When the other options get awkward, write a few lines of JavaScript in a Code step:
Click Add Step, open Built-in, choose Code, then Run JavaScript.
Under Input Params, add one entry per value the code needs. The key is the variable name in your code, and the value is a reference, alone in the field so that lists and objects keep their type:
Key Value orders$.<Get orders>.output.body.ordersWrite the code. Each input is already a variable. Whatever you
returnbecomes the step's output:jsconst paid = orders.filter((o) => o.status === "paid"); return { count: paid.length, total: paid.reduce((sum, o) => sum + o.total, 0), customers: paid.map((o) => o.customer), };
Later steps read the result from the step's results, for example $.<Code step>.output.results.total.
Things to know:
- Don't put references in the code itself. Pass them in through Input Params.
- Input variables can't be reassigned. Copy one first:
let list = [...orders];. console.log(...)lines appear in the step'slogs, which helps when debugging in Executions.- The libraries
radash,dateFns,dateFnsTz,Decimalandnanoidare available without importing them. - Code must finish within 30 seconds. Call APIs with an HTTP step, not from code.
- If the code throws an error, the step fails. See Handle errors and retries.
If you find yourself pasting the same code into several flows, save it once as a Function instead.