Dynamic content allows your workflows to respond to real data — request parameters, action results, headers, and more. Instead of hardcoding values, you use template syntax to reference and transform data at runtime.
You can create dynamic content in two ways:
Content Editor — Visual interface in the dashboard for building dynamic values with helper panels
Template Syntax — Code-based expressions in YAML configuration files
Any text input field that displays the expand icon (⋮⋮) supports dynamic content.
The Content Editor
The Content Editor is a popup interface that helps you build dynamic content with access to variables, functions, and control structures.
Opening the Content Editor
To open the Content Editor:
Click on any text input field in a node’s configuration panel
Look for the expand icon (⋮⋮) in the corner of the field
Click the icon to open the “Edit Content” popup
Editor Layout
The Content Editor has two main areas:
Left panel — Collapsible sections for Variables, Functions, and Control Structures
Right panel — Code editor where you write your dynamic content
Use the Search field to filter available options. Click Apply to save your changes or Cancel to discard them.
Variables Panel
The Variables panel lists all action results available from previous steps in your workflow.
Each variable shows:
Name — The action’s display name (e.g., “AI Agent’s Result”)
Variable reference — The internal ID to use in templates
Description — What data the variable contains
Click a variable to insert it into the editor. Hover over a variable to see its documentation.
Variables are only available from actions that execute before the current step in your workflow. If you don’t see an expected variable, check that the action is connected earlier in the flow.
Functions Panel
The Functions panel lists 19 available functions for transforming and validating data. Functions are organized by purpose:
String manipulation (strip, upper, lower, escape)
Data transformation (jsonout, pluck)
Comparison and validation (eq, notempty, email)
Click a function to insert it with placeholder syntax like ${1:string}. Replace the placeholder with your actual value.
Control Structures Panel
The Control Structures panel provides 4 structures for conditional logic:
if / else — Conditional rendering
range — Iteration over collections
with — Scoped variable access
Template Syntax
ServFlow uses Go’s text/template syntax for dynamic values. The syntax you use depends on where you’re editing.
Full Template Mode
Most input fields use full template mode, where expressions must be wrapped in {{ }} delimiters.
# Simple variable reference
value : "{{ .fetch_user.name }}"
# Request parameter
value : "{{ param \" email \" }}"
# With transformation
value : "{{ param \" email \" | lower }}"
# Combining static and dynamic content
value : "Hello, {{ .fetch_user.name }}!"
Expression Mode
Structured conditional fields (Field and Comparison inputs) use expression mode, where you write raw expressions without {{ }} delimiters. The system automatically wraps your expression.
# In structured conditionals, write raw expressions:
content : .user.email
comparison : param "email"
# NOT like this:
content : "{{ .user.email }}" # Wrong for structured conditionals
See the Conditionals documentation for details on structured vs template conditionals.
Accessing Data
Dynamic content can reference data from multiple sources throughout your workflow.
Action Results
Access results from previous actions using the action ID with a dot prefix:
# Full result from action 'fetch_user'
value : "{{ .fetch_user }}"
# Nested field access
value : "{{ .fetch_user.email }}"
# Array index access
value : "{{ index .fetch_user 0 }}"
# Field from array element
value : "{{ (index .fetch_users 0).email }}"
Request Parameters
Access request body fields and query parameters with the param function:
# Get a parameter
value : "{{ param \" email \" }}"
# Use in filters
filters :
- field : email
operator : eq
value : "{{ param \" email \" }}"
Access HTTP headers with the header function:
# Get Authorization header
value : "{{ header \" Authorization \" }}"
# Extract Bearer token
value : "{{ header \" Authorization \" | trimPrefix \" Bearer \" }}"
When an action is called from an AI agent’s workflow tool, access tool parameters:
# Get tool parameter
value : "{{ tool_param \" search_term \" }}"
Secrets
Access securely stored environment variables with the secret function:
# Get secret value
value : "{{ secret \" API_KEY \" }}"
value : "{{ secret \" DATABASE_URL \" }}"
Available Functions
String Functions
Function Description Example trimPrefixRemove prefix from string {{ header "Auth" | trimPrefix "Bearer " }}trimSuffixRemove suffix from string {{ .path | trimSuffix "/" }}upperConvert to uppercase {{ .name | upper }}lowerConvert to lowercase {{ .email | lower }}replaceReplace substring {{ replace .text "old" "new" -1 }}printfFormat string {{ printf "%s-%d" .name .id }}stripStrip whitespace {{ .input | strip }}escapeEscape special characters {{ .text | escape }}stringescapeEscape string for JSON {{ param "query" | stringescape }}
Comparison Functions
Function Description Example eqEqual {{ eq .status "active" }}neNot equal {{ ne .status "deleted" }}ltLess than {{ lt .age 18 }}leLess than or equal {{ le .price 100 }}gtGreater than {{ gt .count 0 }}geGreater than or equal {{ ge .balance 0 }}
Logical Functions
Function Description Example andLogical AND {{ and .isActive .isVerified }}orLogical OR {{ or .isAdmin .isModerator }}notLogical NOT {{ not .isDeleted }}
Collection Functions
Function Description Example lenGet length {{ len .items }}indexGet element by index {{ index .items 0 }}firstGet first element {{ first .items }}lastGet last element {{ last .items }}pluckExtract field from array {{ pluck .users "email" }}
Data Functions
Function Description Example jsonoutJSON encode value {{ jsonout .data }}jsonrawRaw JSON output {{ jsonraw .data }}defaultDefault value if empty {{ default .name "Unknown" }}nowCurrent timestamp {{ now }}
Validation Functions
These functions are primarily used in conditionals and collect validation errors:
Function Description Example emailValidate email format {{ email (param "email") "Email" }}emptyCheck if empty {{ empty .field "Field" }}notemptyCheck if not empty {{ notempty (param "name") "Name" true }}bcryptCompare bcrypt hash {{ bcrypt (param "password") .user.hash "Password" }}
Pipelines
Chain multiple functions together using the pipe operator |. Data flows left to right through each function:
# Chain multiple operations
value : "{{ param \" email \" | lower | trimPrefix \" mailto: \" }}"
# Format and transform
value : "{{ .user.name | upper }}"
# Default with transformation
value : "{{ param \" status \" | default \" pending \" | upper }}"
# Complex pipeline
value : "{{ header \" Authorization \" | trimPrefix \" Bearer \" | strip }}"
Control Structures
If/Else
Conditionally render content based on a value:
value : "{{ if .isAdmin }}Admin{{ else }}User{{ end }}"
# With comparison
value : "{{ if eq .status \" active \" }}Active{{ else }}Inactive{{ end }}"
With Block
Create a scoped context for nested access:
value : "{{ with .user }}{{ .name }} ({{ .email }}){{ end }}"
Range (Iteration)
Iterate over collections:
value : "{{ range .items }}{{ .name }}, {{ end }}"
For complex array processing, consider using a JavaScript action instead of range loops in templates.
Common Patterns
value : "{{ header \" Authorization \" | trimPrefix \" Bearer \" }}"
Default Values
# Default for missing parameter
value : "{{ default (param \" page \" ) \" 1 \" }}"
# Default for missing field
value : "{{ default .user.avatar \" /images/default.png \" }}"
Safe Strings for JSON
# Escape user input in JSON
filterQuery : '{"name": "{{ param "name" | stringescape }}"}'
# Convert object to JSON
template : '{"data": {{ jsonout .results }}}'
Combining Multiple Values
# String concatenation
value : "{{ param \" firstName \" }} {{ param \" lastName \" }}"
# Using printf
value : "{{ printf \" %s %s \" (param \" firstName \" ) (param \" lastName \" ) }}"
Conditional Display
value : "{{ if .user.isVerified }}Verified{{ else }}Unverified{{ end }}"
Checking Collection Length
# Has results
expression : "{{ gt (len .fetch_results) 0 }}"
# Is empty
expression : "{{ eq (len .items) 0 }}"
Best Practices
Use direct action access — Prefer .actionID syntax for accessing action results
Escape user input — Always use stringescape for user input in JSON or database queries
Provide defaults — Use the default function for optional values to prevent empty outputs
Keep templates simple — Move complex logic to JavaScript actions when templates become difficult to read
Use multi-line YAML — For complex templates, use | for better readability:
value : |
{{ if .user }}
Hello, {{ .user.name }}!
{{ else }}
Hello, Guest!
{{ end }}
Validate early — Use conditionals to validate inputs before processing them in actions
Next Steps
Actions Learn about actions — the building blocks of workflows.
Conditionals Add branching logic to your workflows.
Configuration Reference See the complete ServFlow configuration options.
Secrets Management Securely store credentials for your workflows.