Common expression patterns
Battle-tested recipes for things you'll write often. Copy, adjust, ship.
1. Pull a webhook field into an HTTP body
{
"user_id": "{{ $trigger.body.userId }}",
"amount": {{ $trigger.body.amount }}
}Note the quotes: user_id is a string (use quotes), amount is a number (no quotes, the expression resolves to the raw number).
2. Build a URL with path params
https://{{ $env.API_HOST }}/users/{{ $trigger.body.userId }}/ordersUse $env for the base URL so it varies per environment without changing the workflow.
3. Compose a Slack-style message
:tada: Order {{ $trigger.body.orderId }} from *{{ $trigger.body.customerName }}* — total ${{ $trigger.body.amount }}Mix literal text and expressions freely. Slack-style markdown (*bold*, _italic_, code ) is just literal characters from Flero's perspective.
4. Date for a filename
report-{{ $node["DateTime: now"].json.dateString }}.pdfUse the DateTime Operations node to produce the date string in the format you want, then reference it.
5. Conditional content via an If
Flero doesn't have a ternary inside {{ }}. Use an If node to branch and assemble two different downstream nodes.
For minor conditional content inside a single string, use a Code node:
// Code node
return {
greeting: `Hello, ${input.firstName || "there"}!`
};Then reference {{ $node["Greeting"].json.greeting }} downstream.
6. Join an array into a CSV string
[Loop over items] → [Set: csvRow = "{{ $input.id }},{{ $input.name }},{{ $input.total }}"]
→ [Done] → [Data Transform: join all rows with "\n"]The Text Processing node has a join operation that does this in one step.
7. Cap a value with min / max
{{ $trigger.body.amount }} // if you trust the upstreamIf you need to clamp, use a Data Transform with calculate, or a Code node:
return { capped: Math.min(input.amount, 10000) };8. Default for a missing field
[Data Transform: map { name: $input.name }] // fails if name is missingBetter, explicit default via a Data Transform map:
Operations:
- map:
name: {{ $input.name }}
- map:
name: {{ $input.name }} # overwrites only if previous step was nullThe cleanest pattern is still a small Code node:
return { name: input.name ?? "Anonymous" };9. Reference a deeply nested field with a long path
{{ $node["GraphQL Response"].json.data.user.organization.subscription.plan.tier }}Long paths are normal. Break into multiple Set checkpoints if you reference the same subtree several times:
[Set: subscription = $node["GraphQL Response"].json.data.user.organization.subscription]
[Downstream: {{ $node["Set: subscription"].json.plan.tier }}]10. Use a field from each Loop iteration
// Inside the Loop body — references the current item
{{ $input.email }}
// Equivalent
{{ $node["Loop"].json.email }}$input is more concise inside loops. Use whichever reads better in context.
11. Webhook signature verification
[Webhook Trigger: secret = $env.STRIPE_WEBHOOK_SECRET]
↓
[If: $trigger.headers["stripe-signature"] isNotEmpty]
true → continue
false → [Terminal: status = failed, message = "missing signature"]For deeper validation (compute HMAC, compare to header), use an Encryption/Hashing node with the hmac operation.
12. Idempotency via Cache Storage
[Webhook Trigger]
↓
[Cache: exists? key = "webhook:{{ $trigger.body.id }}"]
↓
[If: exists isTrue]
true → [Terminal: skip, duplicate]
false → [Cache: set, key = same, value = 1, ttl = 86400] → [continue]Prevents the same webhook delivery from doing the real work twice.
Related
- Data Transform
- Recipes, full workflows that use these patterns
- Debugging expressions
Found something out of date? This page lives in the Flero docs content set.