Expressions let workflow inputs be dynamic. The base expression feature provides evaluator infrastructure; language modules add concrete evaluators, descriptors, activities, and type/function definitions.
The base project is [Elsa.Expressions](../../src/modules/Elsa.Expressions). It is intentionally small and does not own language-specific runtime behavior.
## Language Modules
| Module | Feature | Evaluator | Notes |
| --- | --- | --- | --- |
| [Elsa.Expressions.JavaScript](../../src/modules/Elsa.Expressions.JavaScript) | [JavaScriptFeature](../../src/modules/Elsa.Expressions.JavaScript/Features/JavaScriptFeature.cs) | Jint-backed `IJavaScriptEvaluator` | Adds type definitions, function definitions, `RunJavaScript`, and FastEndpoints assembly. |
Additional JavaScript libraries are in [Elsa.Expressions.JavaScript.Libraries](../../src/modules/Elsa.Expressions.JavaScript.Libraries), including Lodash, Lodash FP, and Moment feature packages.
## CSharp
[CSharpFeature](../../src/modules/Elsa.Expressions.CSharp/Features/CSharpFeature.cs) registers C# descriptors and `ICSharpEvaluator`, then adds activities from its assembly. The reference server demonstrates configuring wrappers and appending helper scripts:
Roslyn C# scripting is privileged host-code execution, not a sandbox. Hosts must explicitly set `CSharpOptions.AllowHostCodeExecution` to `true` before C# expressions or `RunCSharp` can be authored or executed. That switch is the whole control: there is no per-caller permission, because a workflow runs under the server's authority rather than the caller's, so gating the caller never constrained what a script could do. Any author who may write workflow definitions may use C# where the switch is on. If only some of your authors are trusted with host code, give the others a host with the switch off — see [#7975](https://github.com/elsa-workflows/elsa-core/issues/7975).
[PythonFeature](../../src/modules/Elsa.Expressions.Python/Features/PythonFeature.cs) registers pythonnet-based evaluation and configures `PythonGlobalInterpreterManager` as a hosted service. Python.NET execution is privileged host-code execution, not a sandbox. Python code can access host process capabilities through pythonnet and must only be enabled for trusted workflow authors.
Hosts must explicitly set `PythonOptions.AllowHostCodeExecution` to `true` before Python expressions or `RunPython` can be authored or executed. As with C#, that switch is the whole control and there is no per-caller permission; the switches are independent, so Python can be enabled while C# stays off. Hosts must also configure the Python DLL path or set `PYTHONNET_PYDLL`.
The reference server configures the Fluid encoder to `HtmlEncoder.Default`.
## Expression Descriptors
Expression descriptors let Studio know which expression languages are available and how to present them. Providers are registered by language features, for example:
-`JavaScriptExpressionDescriptorProvider`
-`CSharpExpressionDescriptorProvider`
-`PythonExpressionDescriptorProvider`
-`LiquidExpressionDescriptorProvider`
The API exposes descriptors under `/elsa/api/descriptors/expression-descriptors`.
## Type Aliases
Expression modules and activity modules register type aliases through `ExpressionOptions`. HTTP, for example, adds aliases such as `HttpRequest`, `HttpResponse`, `RouteData`, `FormFile`, and `Downloadable` in [HttpFeature](../../src/modules/Elsa.Http/Features/HttpFeature.cs).
## ElsaScript Relationship
ElsaScript does not replace expression languages. It uses Elsa's expression providers through language prefixes such as `js =>`, `cs =>`, `py =>`, and `liquid =>`. See [ElsaScript README](../../src/modules/Elsa.Dsl.ElsaScript/README.md).
- workflow integration tests under [test/integration/Elsa.Workflows.IntegrationTests/Evaluation](../../test/integration/Elsa.Workflows.IntegrationTests/Evaluation)
Prefer unit tests for parser/evaluator behavior and integration tests when expression evaluation interacts with workflow variables, activity outputs, or designer descriptors.