Workflow Forms
Workflow Forms bind form definitions to workflow activities through the FormsPlugin. Each activity renders the correct form with fields mapped to process parameters. The plugin manages form versions, draft persistence, and command execution. The Forms API publishes these operations through Workflow Engine HTTP API. Applications that do not use Workflow Engine Web API, including hosts without HTTP, can call FormsRuntimeApi directly. Forms can be versioned independently of process schemes, and each version is stored alongside process data.
Without Workflow Forms, you build a custom data entry screen for every activity in every workflow scheme. An expense report with three approval steps needs three different UIs, each hardcoded to that step's fields. Adding a step means building another UI and redeploying.
Workflow Forms tie form definitions to workflow activities so that each activity renders the right form, with fields mapped to process parameters, without custom UI code per step.
With Workflow Forms, you can define a form once on each activity in the scheme and have your application render it automatically. For example, an expense approval workflow defines an "Expense Details" form on the submit activity, a "Manager Review" form on the approval activity, and a "Finance Approval" form on the final sign-off - each with fields mapped to process parameters, each served by the runtime without per-activity UI code.
What it is
Think of an airport departure board. Each gate shows the right flight information for that gate - passengers at gate A see gate A's flight details, passengers at gate B see gate B's. Workflow Forms work the same way: each activity in a workflow scheme has its own form definition, and when a process instance reaches that activity, the runtime surfaces the correct form for that step.
The Forms Plugin adds a "Show Form" custom activity type to the Designer. When you add this activity to a scheme, you configure which form it should display, which process parameters the form reads from and writes to, and which commands (approve, reject, submit) the form should expose. Form definitions are stored in the database through the IFormDataProvider persistence interface - the same provider that stores schemes and process instances.
For a browser or another HTTP client, the Workflow Engine HTTP API can publish the Forms API. Its five operations retrieve a standalone form, retrieve a process-bound form, discover executable forms, save a draft, and execute a form command. The HTTP layer calls FormsRuntimeApi inside the host; the browser does not call the .NET API directly.
For developers: Install OptimaJet.Workflow.Api.Forms, which includes the Forms Plugin dependency. In the same service configuration that calls AddWorkflowApiCore(), call services.AddFormsPlugin(...) to register both the runtime integration and Forms API operation group. The existing app.MapWorkflowApi() call then publishes the five POST endpoints under the configured base path and /forms, so a custom forms controller is not required.
If the HTTP contract and process parameters use different property-name conventions, register a conversion step with services.AddFormDataPipelineStep<TStep>(order). Incoming form data passes through the steps in ascending order; outgoing form data passes through the same steps in reverse order. The package includes CamelCaseFormsApiFormDataPipeline for lower camel case HTTP keys and Pascal case runtime keys.
If you do not want to use Workflow Engine Web API, install WorkflowEngine.NETCore-FormsPlugin and register FormsPlugin directly during WorkflowRuntime configuration. This manual path also supports hosts that do not expose HTTP. Register the plugin once while configuring the runtime:
using OptimaJet.Workflow.Core.Runtime;using OptimaJet.Workflow.Plugins.FormsPlugin;public static class FormsConfiguration{ public static void RegisterFormsPlugin(WorkflowRuntime runtime) { var settings = new FormsPluginSettings { FormsManagerUrl = "https://forms.example.com" }; runtime.WithPlugin(new FormsPlugin(settings)); }}Later, application code retrieves the registered FormsRuntimeApi and calls it without registering the plugin again:
using System.Threading.Tasks;using OptimaJet.Workflow.Core.Runtime;using OptimaJet.Workflow.Plugins.FormsPlugin;public static class FormsUsage{ public static Task<GetFormResult> GetFormAsync(WorkflowRuntime runtime) { FormsRuntimeApi formsApi = runtime.GetFormsRuntimeApi(); return formsApi.GetFormAsync( new GetFormParameters { FormKey = new FormKey { FormName = "ExpenseDetails" } }); }}The usage example assumes that ExpenseDetails is already stored in the persistence provider. GetFormAsync() loads that standalone definition. GetProcessFormAsync() loads a process-bound form, GetExecutableFormsAsync() discovers forms for the current activity, SaveFormAsync() persists draft data, and ExecuteFormAsync() submits data and executes the associated command.
Why it matters
Workflow Forms deliver these outcomes:
- No per-activity UI code - Define forms on activities in the Designer instead of building custom screens for workflow steps that need user input. The runtime surfaces the right form automatically.
- Forms evolve with schemes - Change a form definition or add a new activity with its own form without redeploying your application. The Designer stores form versions, and the plugin resolves the current version at runtime.
- Parameter mapping is built in - Form fields map directly to process parameters. Submit a form and the runtime writes field values to parameters and executes the associated command in one operation.
- Draft support out of the box - The plugin manages draft data per form and per activity. A user can start filling a form, save progress, and return later without losing data.
Who it is for
Evaluator (CEO, CTO, PM): Workflow Forms remove the bottleneck of building custom UIs for workflow steps that need user input. Your team designs forms in the Designer alongside the process flow, not in a separate frontend sprint.
Developer: Register OptimaJet.Workflow.Api.Forms with services.AddFormsPlugin(...), configure the FormsManagerUrl, and add the "Show Form" custom activity to schemes. Frontends call the Forms API to fetch forms, save drafts, and submit data. Applications that do not use Workflow Engine Web API can register FormsPlugin directly and call FormsRuntimeApi instead.
Enterprise architect: Forms are stored as versioned definitions in the same persistence provider as process data. The plugin integrates with the runtime's existing rule provider for permission checks on form field access and command execution.
When to use it
Use Workflow Forms when some activities in your workflow need user input and you want the form-to-activity mapping managed by the runtime instead of hardcoded in your application. Typical examples:
- Structured approval workflows - An expense report shows an "Expense Details" form at submission, a "Manager Review" form at approval, and a "Finance Approval" form at final sign-off. Each form has different fields and different associated commands.
- Onboarding sequences - A new employee onboarding workflow shows a "Personal Details" form, then a "Department Setup" form, then an "IT Access Request" form - each at a different activity in the same scheme.
- Case management - A customer support workflow presents different forms depending on the case type. The scheme routes to the appropriate activity, and the plugin resolves the form definition for that activity.
- Multi-version form deployments - Update a form definition while instances are running. Previous instances use the form version that was current when they reached the activity; new instances use the updated version.
How it compares
The table below shows the tradeoffs between the Workflow Engine approach and the alternative.
| Approach | What it requires | Result |
|---|---|---|
| Build custom UIs per activity | Build, test, and deploy a separate data entry screen for every workflow step | High development effort, tightly coupled to scheme changes, redeployment required for each form change |
| Workflow Forms | Define forms on activities; use Forms API over HTTP or FormsRuntimeApi in .NET | Forms managed alongside the scheme, parameter mapping built in, no per-activity UI code |
The Forms Plugin gives you the flexibility of the schema-driven approach without forcing you into a specific frontend framework. Your application decides how to render forms; the plugin handles discovery, parameter mapping, validation, and persistence.
See also
Workflow Engine Editions
Which editions and licenses support the Forms Plugin.
HTTP API
Publish Forms API endpoints for browser and service clients.
Frequently asked questions
Do Workflow Forms require a specific license?
Yes. The Forms Plugin is a license-gated feature. Your license must include the "Forms" capability. See Workflow Engine Editions for licensing details.
Which databases support the Forms Plugin?
Any database that has a persistence provider implementing IFormDataProvider. All six built-in providers - SQL Server, PostgreSQL, MySQL, MongoDB, Oracle, and SQLite - include form storage support. The form schema and version data are stored in a forms table created during provider migration.
How do form fields relate to process parameters?
Each form defines input parameters (data loaded into the form), output parameters (data written when a command executes), and draft parameters (progress saved mid-form). These are configured in FormSettings when setting up the "Show Form" activity. The plugin reads and writes the named process parameters automatically on form submission.
Can I use the Forms Plugin with a custom frontend framework?
Yes. The plugin ships with frontend packages (@optimajet/workflow-forms-manager and @optimajet/workflow-forms-viewer) for React. A custom frontend can call the Forms API, which returns structured form definitions and data rather than pre-rendered HTML. If the application does not use Workflow Engine Web API, including when its host does not expose HTTP, application code can register FormsPlugin manually and call FormsRuntimeApi directly.
What happens to in-progress forms when the form definition is updated?
The plugin stores form versions. A process instance that has already loaded a form uses the definition version that was current when the form was displayed. Only new form loads (new process instances reaching the activity after the update) use the latest version. You can manage versions through the Designer's form management actions.