Expressions
Learn how Elsa Studio expression editors map to Elsa Server expression engines, how to access workflow variables, and which syntax choices are actually available in Elsa 3.8.
Elsa Studio lets you enter activity values in different expression syntaxes. The exact choices you see are not hardcoded in Studio alone: Studio asks Elsa Server for the available expression descriptors and renders those options in the property editor.
This matters for two reasons:
The list of available expression types depends on which expression features your server enables.
Some syntaxes shown in Studio are UI helpers, while others are real runtime expression engines.
How expression selection works
For most activity inputs, Studio shows a Default option plus one or more code-oriented expression types.
Default means: use the activity's normal UI editor for that field.
Literal and Object are built-in Studio/UI syntaxes used behind the scenes for plain values and structured values.
JavaScript, Liquid, C#, Python, and other custom types are provided by the server.
In the 3.8 sample server, the app enables these expression engines:
.UseCSharp(...)
.UseJavaScript(...)
.UsePython(...)
.UseLiquid(...)If your server does not register one of these features, Studio will not offer that syntax.
In Elsa 3.8, C# and Python are only browsable in Studio when host code execution is allowed for those engines. If you do not see them in the picker, check your server configuration first.
Expression matrix
The following matrix separates what Studio shows from what the backend actually evaluates.
Default
Studio UI mode
Field-specific editor
Not a separate runtime expression engine.
Variable
Server descriptor
Picker UI
Resolves to a selected workflow variable. Different from variables in JavaScript or Variable in C#.
Input
Server descriptor
Picker UI
Resolves to a selected workflow input. Different from getInput(...) or C# Input.
JavaScript
UseJavaScript(...)
Monaco code editor
Best general-purpose dynamic option in Studio.
Liquid
UseLiquid(...)
Monaco code editor
Best for text templates.
C#
UseCSharp(...)
Monaco code editor
Browsable only when host code execution is allowed.
Python
UsePython(...)
Monaco code editor
Browsable only when host code execution is allowed.
Custom types such as Secret
Feature-specific descriptor
Usually picker or custom UI
Only appears when the related backend feature is installed.
Studio also has hidden internal descriptors such as Literal and Object that support plain values and structured values behind the scenes.
Which syntax should you use?
Use the simplest option that matches the job:
Default for plain text, numbers, booleans, dropdowns, and other normal field editors.
Variable when you want the field to resolve directly from a selected workflow variable without writing code.
Input when you want the field to resolve from a selected workflow input without writing code.
JavaScript for most dynamic value composition and workflow-variable lookups.
Liquid for templated text output.
C# when you explicitly want Roslyn-based expressions and have enabled them for trusted authors.
Python only when your server is configured for Python.NET expressions and you need it specifically.
Picker syntaxes versus code-expression objects
This is the most common point of confusion in Studio:
Variable and Input in the syntax picker are expression types backed by picker UI.
variablesin JavaScript is a runtime object injected into the JavaScript engine.VariableandInputin C# are runtime proxies injected into the C# evaluator.
So these are related, but they are not the same thing.
Variable picker
Use Variable when a property should simply read from one workflow variable and you do not need any extra logic.
Example: choose the CustomerName variable from the picker for a text field.
Input picker
Use Input when a property should read directly from one declared workflow input.
Example: choose the OrderId workflow input from the picker for a downstream activity field.
JavaScript expressions
JavaScript is usually the most convenient dynamic syntax in Studio.
Reading variables
If variable wrappers are enabled and your variable names are valid JavaScript property names, you can use:
Elsa also exposes explicit helper functions:
Use getVariable when:
the variable name is not a valid JavaScript identifier.
variable wrappers were disabled on the server.
you want to avoid depending on the
variables.SomeNameconvenience wrapper.
Writing variables
To assign a value from JavaScript, use:
Accessing inputs and outputs
Elsa's JavaScript helpers also include:
Practical JavaScript examples
Important wrapper limitation
The variables.SomeName style depends on two JavaScript runtime settings:
variable wrappers must be enabled.
variable copying must be enabled.
If either is disabled, use getVariable(...) and setVariable(...) instead.
C# expressions
C# expressions are available when the server enables the C# expression feature and allows host code execution for trusted workflow authors.
Elsa generates a variable proxy for C# expressions. In Elsa 3.8, both Variables and Variable work, but Variable is the preferred alias.
Reading variables
Writing variables
Accessing inputs and outputs
Accessing workflow metadata
You can also assign metadata in C# expressions when the scenario supports it:
Practical C# examples
When to prefer Get<T>()
Get<T>()Use Get<T>() when:
the variable name is not a valid generated property name.
you want explicit typing.
wrappers were disabled in C# options.
Liquid expressions
Liquid is best for text templating.
Elsa 3.8 registers workflow variables through the Variables object and workflow or activity inputs through Input.
Liquid also exposes workflow metadata:
Practical Liquid examples
Use Liquid when the result should primarily be formatted text, not when you need more procedural logic.
Python expressions
Python expressions are available only when the Python feature is enabled and host code execution is allowed.
Elsa injects these globals into the Python scope:
execution_contextinputoutputoutcomevariables
Typical variable access looks like this:
Accessing inputs and outputs
Practical Python examples
Python expressions are executed through Python.NET in Elsa 3.8. Keep them for intentionally enabled, trusted-author scenarios rather than as the default authoring path in Studio.
Feature-specific custom expression types
Studio can also surface feature-specific expression types beyond the core set above.
For example, Elsa's secrets feature contributes a Secret expression descriptor with its own custom UI instead of a code editor. The general rule is:
if a backend feature registers an expression descriptor and marks it browsable, Studio can show it.
if the descriptor provides a custom
UIHint, Studio renders that custom picker/editor instead of Monaco.
That is why two Elsa deployments can show different syntax choices for the same activity field.
Variable naming guidance
If you want the most convenient cross-language experience in Studio, use variable names that are valid identifiers, such as:
OrderIdCustomerNameRetryCount
Avoid names that require quoting or special handling, such as:
order-idcustomer name123value
Those names can still work, but you will need accessor methods like getVariable("order-id") instead of wrapper-style property access.
Variable storage and expressions
Expressions read the current value of workflow variables regardless of whether the variable is stored in memory or in workflow-instance storage.
In Elsa 3.8:
Memory storage keeps the value in memory for the lifetime of the current execution context.
Workflow Instance storage persists the value in workflow state.
The legacy Workflow storage driver still exists for backward compatibility, but
Workflow Instanceis the current persisted option.
Choose storage based on lifecycle and suspension/resumption needs; choose expression syntax based on authoring convenience.
Recommended patterns
Use Default unless you actually need dynamic behavior.
Use JavaScript for most dynamic field values in Studio.
Use Liquid for generated messages, templates, and text bodies.
Use C# and Python only for trusted-author scenarios where you intentionally enable host code execution.
Prefer identifier-friendly variable names so wrapper syntax stays simple.
Common pitfalls
"I don't see C# or Python in Studio"
Usually this means the backend did not enable that engine, or host code execution for that engine is disabled.
"variables.MyValue does not work in JavaScript"
variables.MyValue does not work in JavaScript"Check these first:
the variable name is a valid identifier.
JavaScript variable wrappers were not disabled.
JavaScript variable copying was not disabled.
If any of those are not true, switch to:
"My field shows Default instead of a code editor"
That is normal. Default uses the activity's UI hint. Switch the syntax picker to a code-backed expression type such as JavaScript or Liquid if you want to write an expression.
See also
Last updated