Short answer. Workflow Engine NEO by Optimajet fits .NET products built around business state, human decisions, forms and tenant isolation. Elsa Workflows fits products built around technical orchestration, events, integrations and background work. In a multi-tenant approval product, Workflow Engine NEO supplies the Commands, permission checks, Inbox, Forms Plugin, tenant routing and process locks. With Elsa, the team adds an external task and forms layer and configures a distributed runtime, locking and scheduling for several nodes.
I am Rylee Soll. I lead the product team of Workflow Engine NEO at Optimajet, and I run our demos. Most weeks someone on a demo call asks why they should pay for a license when Elsa Workflows is MIT. A feature list cannot answer that. So I built one approval process in both engines and wrote down what each engine takes over and what stays in the application.
This post is the short version. The full comparison of Elsa Workflows and Workflow Engine NEO has the diagrams and both workflow definitions in C#. Every claim about Elsa in it links to Elsa's own documentation.
The approval process I built twice
The test case is a document approval. An employee submits a document, and a manager approves or rejects it. If the manager misses a three-day deadline, the process escalates to a senior manager.
The two engines model it differently. Workflow Engine NEO treats it as the lifecycle of the document. An Activity called ManagerReview carries the State "Under review". Two Commands, Approve and Reject, trigger the Transitions out of it, and only the manager may run them. A Timer moves the process to Escalated when the deadline passes. Elsa treats the same process as a graph of executable activities. A Fork in WaitAny mode runs two branches. A RunTask waits for the manager, and a Timer waits for the deadline. The first branch to finish cancels the other. How the workflow models differ shows both on one diagram.
The happy path says little about a workflow engine. I followed the process further, to where the state lives, what survives a restart, how two tenants stay apart, and what somebody has to operate at three in the morning. I compared Elsa 3.7, as its documentation stood in August 2026, with Workflow Engine NEO v22.
Who owns what
In both products, your application keeps its identity, its services and its business data. The difference is the block marked "You provide". With Workflow Engine NEO, it holds an Action Provider, which calls your services, and a Rule Provider, which checks identities. With Elsa, it holds custom activities and the whole human-task layer, including assignment, the Inbox, forms and the business audit.
For the approval process, the split looks like this.
| Part of the approval | Workflow Engine NEO v22 | Elsa Workflows 3.7 |
|---|---|---|
| Decisions a user can take now | Workflow Runtime returns the Commands available to that user at the current Activity | Your task layer decides. Elsa's instance API does not list named business decisions |
| Who may approve | Restrictions reference Actors, and your Rule Provider checks the user's Identity | Your task layer checks the manager before it completes the task |
| Inbox and forms | Approval Plugin Inbox and Forms Plugin | Your team builds them or connects an existing task platform |
| Deadline and escalation | A Timer-triggered Transition moves the process to Escalated
|
The timer branch of Fork(WaitAny) wins, and your task layer closes or expires the task |
| Timers on several nodes | TimerManager polls due timers in batches from the shared database | Distributed Runtime, distributed locking, and clustered Quartz.NET or Hangfire with shared storage |
| A decision and the deadline at the same moment | A lock on the process instance lets only one of them run | The distributed runtime serializes execution, and your task layer must update the task atomically |
| Tenants | Logical, physical or hybrid tenancy. Through the HTTP API, the tenant scope covers the Inbox, forms, timers, history and permissions | Shared tables, a database per tenant, or both. Your task and forms layer enforces its own isolation |
| Decision history | Transition History records the route, trigger, actor, executor and time | The workflow journal records the technical flow, and your application writes the business audit |
| Code you still write | A Rule Provider, Actions and forms | A task and forms layer, plus application activities (four in this example) |
Both engines persist long waits, version their definitions, support visual and code-first authoring, run child workflows and support multitenancy. What differs is how much of the human-task layer comes with the product.
Where the difference shows up
Human tasks and permissions
In Workflow Engine NEO, a decision is a Command on a Transition. Workflow Runtime lists the Commands that a user may run at the current Activity. When you ask it to, it checks the Rules again as the manager submits the decision.
In Elsa, RunTask creates a task ID and a bookmark, sends a request to your handler, and waits. Your task layer validates the manager and sends the task ID and the result to Elsa's task-completion endpoint, which resumes the workflow. The article draws the application integration for both engines.
A decision and a deadline at the same moment
Say the manager clicks Approve in the same second the deadline fires. In Workflow Engine NEO, the Command or the due timer locks the process instance through persistence, so only one of them runs, even across nodes that share the database. If the deadline wins, Approve is no longer valid.
In Elsa, Fork(WaitAny) cancels the losing branch, but it does not serialize two hosts that loaded the same instance. That takes the distributed runtime and a shared lock. Your task layer must still complete or expire the task atomically and reject a late answer. Concurrent events and process locking walks through the race in both engines.
Timers on more than one node
Workflow Engine NEO keeps timers in its database. TimerManager polls the due ones in batches, and in multi-server mode the runtimes take turns, so no external scheduler is involved.
Elsa's default local scheduler keeps one in-memory task per timer and rebuilds them from stored bookmarks after a restart. On several nodes, Elsa needs Distributed Runtime, distributed locking, and clustered Quartz.NET or Hangfire with durable shared storage. Your team runs and monitors that scheduler. The section on long-running waits in both engines links the Elsa documentation and scheduler source behind these points.
Tenants
Workflow Engine NEO supports logical tenancy in shared tables, physical tenancy in a dedicated database or schema, and hybrid tenancy that mixes the two. The HTTP API reads the tenant from the Workflow-Api-Tenant-ID header and routes the request to that tenant's runtime and database. Its tenant scope covers the Inbox, forms, timers, history and permissions.
Elsa supports shared tables and a database per tenant, and one connection-string factory can mix them. It scopes its own stores, Elsa Identity and the configured scheduler jobs by tenant. It has no built-in router for a schema per tenant, and your task and forms service has to enforce the same isolation on its own data. Multitenancy architecture in both engines compares the storage models in one diagram.
The editor in your frontend
Workflow Designer is a JavaScript component with React and Angular wrappers and Blazor interop. A custom activity type can supply a complete SVG node template. Elsa Studio is a Blazor application. Its custom elements and its React wrapper load the Blazor WebAssembly runtime, which makes the page heavier in JavaScript, React and Angular products. In a Blazor product, Elsa Studio is the more native fit. The article has the details on visual authoring and editor embedding.
When I would choose Elsa
If most of your complexity is events, integrations and background work rather than people and business state, choose Elsa. It is also the better fit in these cases.
- Event and integration pipelines. Triggers and bookmarks, HTTP and MassTransit activities, dispatch, child workflows and parallel branches are Elsa's native model.
-
Code-first workflows owned by developers.
WorkflowBasekeeps typed inputs, outputs and variables in C#. Elsa Studio saves its edits as a separate draft, so the team picks C# or Studio as the source of truth. - Calls to models and tools. The optional Elsa Agents extension turns configured agents into activities and selected skills into functions a model can call.
- Open source as a hard requirement. Elsa Core, Elsa Studio and Elsa's extensions use the MIT license, so you can modify and redistribute them.
Elsa can also cost less when your product already has the task, forms and operations pieces around it.
What the license pays for
Elsa Core is MIT and has no runtime license fee. Paid support and services come from independent providers listed on Elsa+.
The editions and prices of Workflow Engine NEO are on the pricing page. Every edition of Workflow Engine NEO includes Forms integration through the Forms Plugin, and every edition runs on several servers. For the approval product in this test, Workflow Engine NEO supplies the Commands, Rules, the Approval Plugin Inbox, tenant routing, timers and multi-server coordination. Your team configures them instead of building and running its own services for the same jobs.
So compare the price of Workflow Engine NEO with what you would build, run and support around Elsa. That means the task and forms code, the multi-tenant integration, the distributed operations and paid support.
If your Elsa design uses MassTransit, add one more line to the budget. Elsa can use MassTransit for broker-backed messaging, and its distributed-hosting guide uses it for cache invalidation across nodes. The current integration pins MassTransit 8.5.7, under Apache 2.0. MassTransit v9 requires a commercial subscription, and as of September 2026 Elsa has no committed v9 integration. The sources are in licensing and total cost.
Test both before you choose
A comparison ends where a proof of concept begins. Build the same approval in both engines, with a reminder, a deadline, an escalation and two tenants. Restart a host during a wait, race a decision against the deadline on two nodes, and update the definition while an older instance is still running. Then count the code and the deployed components that live outside the definition. Ask a second developer to change one rule without help, and write down how long it took.
For the Workflow Engine NEO side, request a 30-day trial key. If you compare engines with an AI assistant, give it the Markdown version of the full comparison, so it works from the same text you read.
If I read Elsa's documentation wrong anywhere, say so in the comments or in GitHub Discussions, and I will change the row in the full comparison. If you would rather see this against your own process, book a call. I am the person on the other side of it.

Top comments (0)