# Parameter A parameter is a variable that belongs to a [process instance](https://docs.workflowengine.io/get-started/concepts/process-instance/): a typed key-value pair that [WorkflowRuntime](https://docs.workflowengine.io/get-started/concepts/workflow-runtime/) manages throughout the process lifecycle. Parameters carry business data - document IDs, assignee names, approval decisions, computed values. [Actions](https://docs.workflowengine.io/get-started/concepts/action/) read and write parameters; [conditions](https://docs.workflowengine.io/get-started/concepts/condition/) evaluate them; the [scheme](https://docs.workflowengine.io/get-started/concepts/scheme/) can use them to route [transitions](https://docs.workflowengine.io/get-started/concepts/transition/). Think of a parameter as a labeled field on a paper form that moves from desk to desk. When someone submits a vacation request, the `ApproverName` parameter stores who must sign it. When an invoice reaches the Accounting step, `InvoiceAmount` holds the amount to pay. Each step reads and updates these fields - they travel with the process from start to finish. ## What a parameter is A parameter is a named value that a process instance owns. Its name is a string - for example, `ApproverName` or `DocumentId` - and its value has a .NET type such as `int`, `string`, or `DateTime`. The process reads it, writes it, and passes it between steps. `WorkflowRuntime` keeps parameters in memory while the process executes and saves only `Persistence` parameters through the configured persistence provider. Inside actions, you read and write them using `GetParameter` and `SetParameter`. ```csharp filename="Reading and writing a parameter inside an action" // Read a parameter set by a previous action string assignee = processInstance.GetParameter("ApproverName"); int docId = processInstance.GetParameter("DocumentId"); // Write a value for the next step processInstance.SetParameter("Decision", "Approved"); ``` You can also pass initial parameters when creating the instance: ```csharp filename="Creating a process instance with initial parameters" var createInstanceParams = new CreateInstanceParams( schemeCode: "DocumentApproval", processId: Guid.NewGuid() ); createInstanceParams.AddPersistentParameter("DocumentId", 1042); createInstanceParams.AddPersistentParameter("OwnerId", "user-42"); await runtime.CreateInstanceAsync(createInstanceParams); ``` The values are available during instance creation. `Persistence` values are saved through the configured persistence provider. `ParameterPurpose` controls how Workflow Engine handles a parameter: Table: Parameter purpose types | Purpose | Behavior | |---------------|----------------------------------------------------------------------| | `Persistence` | Saved through the persistence provider and available in later runs | | `Temporary` | Kept in memory until the current process execution finishes | | `System` | Maintained by Workflow Engine from process and execution information | Use `Persistence` for data needed after the process becomes idle. Use `Temporary` for values needed only by the execution started by a creation, command, or state change. Parameters are also classified by how they are declared: Table: Parameter definition types | Classification | Description | |----------------|-------------------------------------------------------------------------| | `Explicit` | Declared in the scheme with a known type, purpose, and optional default | | `Implicit` | Created at runtime when a value is first passed or set through code | Most parameters are implicit. You pass them through `SetParameter`, `AddPersistentParameter`, or `AddTemporaryParameter` without declaring them in the scheme first. The engine creates the parameter automatically when the first value arrives. Explicit parameters are declared in the scheme ahead of time with a type, purpose, and optional default value. They are rarely needed and can be useful for auto-generated forms. Only a persistent explicit parameter can have an initial value. ## How a parameter works When an execution starts, `WorkflowRuntime` loads the process instance and fills its persistence parameters from the database into memory. Actions and conditions run against this in-memory copy - `GetParameter` and `SetParameter` calls do not read or write the database directly. After the current execution finishes successfully, `WorkflowRuntime` saves changed `Persistence` parameters. `Temporary` parameters are not saved and are unavailable when the process starts its next execution. The parameter lifecycle for a successful process execution is: You can also pass them with `WorkflowCommand.SetParameter` or `SetStateParams`. A command parameter is temporary by default; pass `persist: true` when the value must be saved. The command execution guide shows the complete flow. ```csharp filename="Passing parameters with a command" var command = (await runtime.GetAvailableCommandsAsync(processId, identityId)).First(); command.SetParameter("Comment", "Needs review"); command.SetParameter("ApprovedAmount", 1500.00m, persist: true); await runtime.ExecuteCommandAsync(command, identityId, identityId); ``` `Comment` is available only during this command execution. `ApprovedAmount` is saved for later executions. The example passes the same identity twice because it does not use impersonation. Calling `SetParameter` without a purpose creates a missing parameter as `Temporary`. Passing `ParameterPurpose.Persistence` creates a persistent implicit parameter. If an existing parameter or its scheme definition is already `Persistence`, setting it without the purpose does not downgrade it to `Temporary`. ## Parameter and process instance A [process instance](https://docs.workflowengine.io/get-started/concepts/process-instance/) is the owner of every process parameter. Actions and conditions attached to the same instance read and write the same parameter set. Two instances created from the same scheme have separate parameter values. `WorkflowRuntime` also maintains system parameters from process and execution information. Examples include `ProcessId`, `SchemeCode`, `CurrentState`, `CurrentActivity`, `IdentityId`, and `ExecutedTransition`. They are available inside actions and conditions without being declared explicitly in the scheme. ## Parameters in conditions Scheme conditions can read process parameters through a code action defined in the scheme. The code action runs during transition evaluation and returns `true` or `false`: ```csharp filename="Reading a parameter in a condition" return processInstance.GetParameter("IsUrgent"); ``` Here, the condition reads `IsUrgent` from the process instance. The scheme connects the condition to a transition. An `Expression` condition can read the same parameter directly with the `@` prefix. For example, `@IsUrgent` returns the Boolean value of the `IsUrgent` parameter without a separate code action. For syntax and examples, see [Condition](https://docs.workflowengine.io/get-started/concepts/condition/). ## Advanced parameter scenarios Parameters support advanced scenarios when the type is unknown at design time, the value is nested inside a complex object, or the data lives outside the workflow database. When the parameter type is not known at design time, read it as `DynamicParameter` and access its properties by name: ```csharp filename="Reading a dynamic parameter" var document = processInstance.GetParameter("Document"); string title = (string)document["Title"]; ``` The same parameter can be read through a C# `dynamic` property: ```csharp filename="Reading a DynamicParameter through dynamic" dynamic document = processInstance.GetParameter("Document"); string title = document.Title; ``` For parameters that hold multi-level objects, dot notation reads or updates one property without replacing the whole object: ```csharp filename="Reading and updating a partial parameter" decimal amount = processInstance.GetParameter("Document.Amount"); processInstance.SetParameter("Document.Amount", amount + 100m); ``` An external parameter is stored outside Workflow Engine but is accessed through the normal `ProcessInstance` parameter API. An `IWorkflowExternalParametersProvider` tells the engine which names it handles and supplies synchronous or asynchronous getters and setters. This minimal provider handles names that start with `External_` and stores values in memory by process ID. A production provider would use the application's data store instead: ```csharp filename="External parameter provider" using System; using System.Collections.Concurrent; using System.Threading.Tasks; using OptimaJet.Workflow.Core.Model; using OptimaJet.Workflow.Core.Runtime; public sealed class InMemoryExternalParameterProvider : IWorkflowExternalParametersProvider { private readonly ConcurrentDictionary<(Guid ProcessId, string Name), object> _values = new(); public bool HasExternalParameter( string parameterName, string schemeCode, ProcessInstance processInstance) { return parameterName.StartsWith("External_", StringComparison.Ordinal); } public bool IsGetExternalParameterAsync( string parameterName, string schemeCode, ProcessInstance processInstance) { return true; } public bool IsSetExternalParameterAsync( string parameterName, string schemeCode, ProcessInstance processInstance) { return true; } public object GetExternalParameter( string parameterName, ProcessInstance processInstance) { _values.TryGetValue((processInstance.ProcessId, parameterName), out object value); return value; } public Task GetExternalParameterAsync( string parameterName, ProcessInstance processInstance) { return Task.FromResult(GetExternalParameter(parameterName, processInstance)); } public void SetExternalParameter( string parameterName, object parameterValue, ProcessInstance processInstance) { _values[(processInstance.ProcessId, parameterName)] = parameterValue; } public Task SetExternalParameterAsync( string parameterName, object parameterValue, ProcessInstance processInstance) { SetExternalParameter(parameterName, parameterValue, processInstance); return Task.CompletedTask; } } ``` Register the provider during runtime setup: ```csharp filename="External parameter provider registration" runtime.WithExternalParametersProvider(new InMemoryExternalParameterProvider()); ``` After registration, workflow code reads `External_Customer` through the normal parameter API. The value remains in the provider's data store rather than being saved as a process parameter: ```csharp filename="Reading an external parameter" dynamic customer = await processInstance.GetParameterAsync("External_Customer"); string name = customer.Name; ``` Dynamic, partial, and external parameters are advanced integration options. They do not change the basic choice between temporary execution data and persistence data owned by the process instance. ## See also - [Action](https://docs.workflowengine.io/get-started/concepts/action/): Actions read and write parameters via GetParameter and SetParameter. - [Transition](https://docs.workflowengine.io/get-started/concepts/transition/): Transitions connect activities and fire when their conditions pass. - [Process Instance](https://docs.workflowengine.io/get-started/concepts/process-instance/): A process instance stores parameters as part of its state. - [Condition](https://docs.workflowengine.io/get-started/concepts/condition/): Conditions use parameter values for routing decisions. ## Frequently asked questions **What is a parameter in Workflow Engine?** A parameter is a variable that belongs to a process instance - a typed key-value pair that `WorkflowRuntime` manages throughout the process lifecycle. Actions read and write parameters; conditions evaluate them to route transitions. **What is the difference between implicit and explicit parameters in Workflow Engine?** An implicit parameter has no scheme definition and is created when code first passes or sets its value. An explicit parameter is declared in the scheme with its CLR type and purpose; a persistent explicit parameter can also define an initial value. **How do I pass initial data to a process instance in Workflow Engine?** Add values to `CreateInstanceParams` with `AddPersistentParameter` or `AddTemporaryParameter` before calling `CreateInstanceAsync`. The values are available during instance creation, and persistent values are saved through the configured provider. **What is the difference between Temporary and Persistence parameters?** A `Temporary` parameter is available only during the current process execution and is not saved. A `Persistence` parameter is saved through the persistence provider and can be loaded for later executions. **What is an external parameter in Workflow Engine?** An external parameter is read and written through an `IWorkflowExternalParametersProvider`. Its value stays in an external data store while workflow code uses the normal `ProcessInstance` parameter API.