<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Optimajet Limited</title>
    <description>The latest articles on DEV Community by Optimajet Limited (@optimajet).</description>
    <link>https://dev.to/optimajet</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1475516%2F326deb07-08af-408b-a5a3-dfa595a8ebb3.png</url>
      <title>DEV Community: Optimajet Limited</title>
      <link>https://dev.to/optimajet</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/optimajet"/>
    <language>en</language>
    <item>
      <title>What Elsa Workflows and Workflow Engine NEO leave in your code</title>
      <dc:creator>Optimajet Limited</dc:creator>
      <pubDate>Wed, 30 Sep 2026 15:43:48 +0000</pubDate>
      <link>https://dev.to/optimajet/what-elsa-workflows-and-workflow-engine-neo-leave-in-your-code-5hm3</link>
      <guid>https://dev.to/optimajet/what-elsa-workflows-and-workflow-engine-neo-leave-in-your-code-5hm3</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Short answer.&lt;/strong&gt; 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.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I am &lt;a href="https://github.com/rylee-soll" rel="noopener noreferrer"&gt;Rylee Soll&lt;/a&gt;. I lead the product team of &lt;a href="https://workflowengine.io/products/workflow-engine-neo/" rel="noopener noreferrer"&gt;Workflow Engine NEO&lt;/a&gt; at Optimajet, and I run our demos. Most weeks someone on a demo call asks why they should pay for a license when &lt;a href="https://www.elsaworkflows.io/" rel="noopener noreferrer"&gt;Elsa Workflows&lt;/a&gt; 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.&lt;/p&gt;

&lt;p&gt;This post is the short version. The &lt;a href="https://workflowengine.io/blog/elsa-vs-workflow-engine/" rel="noopener noreferrer"&gt;full comparison of Elsa Workflows and Workflow Engine NEO&lt;/a&gt; has the diagrams and both workflow definitions in C#. Every claim about Elsa in it links to Elsa's own documentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  The approval process I built twice
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;The two engines model it differently. Workflow Engine NEO treats it as the lifecycle of the document. An Activity called &lt;code&gt;ManagerReview&lt;/code&gt; carries the State "Under review". Two Commands, &lt;code&gt;Approve&lt;/code&gt; and &lt;code&gt;Reject&lt;/code&gt;, trigger the Transitions out of it, and only the manager may run them. A Timer moves the process to &lt;code&gt;Escalated&lt;/code&gt; when the deadline passes. Elsa treats the same process as a graph of executable activities. A &lt;code&gt;Fork&lt;/code&gt; in &lt;code&gt;WaitAny&lt;/code&gt; mode runs two branches. A &lt;code&gt;RunTask&lt;/code&gt; waits for the manager, and a &lt;code&gt;Timer&lt;/code&gt; waits for the deadline. The first branch to finish cancels the other. &lt;a href="https://workflowengine.io/blog/elsa-vs-workflow-engine/#workflow-model" rel="noopener noreferrer"&gt;How the workflow models differ&lt;/a&gt; shows both on one diagram.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who owns what
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkkul75g6wu0nqv9ffuqs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fkkul75g6wu0nqv9ffuqs.png" alt="Diagram of what Workflow Engine NEO and Elsa Workflows bring to an application. Workflow Engine NEO brings Workflow Runtime, persistence, Workflow Designer, the HTTP API, Inbox and Forms Plugin, and the application provides an Action Provider and a Rule Provider. Elsa Workflows brings an activity runtime, hosting and tools, and stores, and the application provides custom activities and the human-task layer." width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the approval process, the split looks like this.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Part of the approval&lt;/th&gt;
&lt;th&gt;Workflow Engine NEO v22&lt;/th&gt;
&lt;th&gt;Elsa Workflows 3.7&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Decisions a user can take now&lt;/td&gt;
&lt;td&gt;Workflow Runtime returns the Commands available to that user at the current Activity&lt;/td&gt;
&lt;td&gt;Your task layer decides. Elsa's instance API does not list named business decisions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Who may approve&lt;/td&gt;
&lt;td&gt;Restrictions reference Actors, and your Rule Provider checks the user's Identity&lt;/td&gt;
&lt;td&gt;Your task layer checks the manager before it completes the task&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Inbox and forms&lt;/td&gt;
&lt;td&gt;Approval Plugin Inbox and Forms Plugin&lt;/td&gt;
&lt;td&gt;Your team builds them or connects an existing task platform&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deadline and escalation&lt;/td&gt;
&lt;td&gt;A Timer-triggered Transition moves the process to &lt;code&gt;Escalated&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;The timer branch of &lt;code&gt;Fork(WaitAny)&lt;/code&gt; wins, and your task layer closes or expires the task&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Timers on several nodes&lt;/td&gt;
&lt;td&gt;TimerManager polls due timers in batches from the shared database&lt;/td&gt;
&lt;td&gt;Distributed Runtime, distributed locking, and clustered Quartz.NET or Hangfire with shared storage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A decision and the deadline at the same moment&lt;/td&gt;
&lt;td&gt;A lock on the process instance lets only one of them run&lt;/td&gt;
&lt;td&gt;The distributed runtime serializes execution, and your task layer must update the task atomically&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tenants&lt;/td&gt;
&lt;td&gt;Logical, physical or hybrid tenancy. Through the HTTP API, the tenant scope covers the Inbox, forms, timers, history and permissions&lt;/td&gt;
&lt;td&gt;Shared tables, a database per tenant, or both. Your task and forms layer enforces its own isolation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Decision history&lt;/td&gt;
&lt;td&gt;Transition History records the route, trigger, actor, executor and time&lt;/td&gt;
&lt;td&gt;The workflow journal records the technical flow, and your application writes the business audit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Code you still write&lt;/td&gt;
&lt;td&gt;A Rule Provider, Actions and forms&lt;/td&gt;
&lt;td&gt;A task and forms layer, plus application activities (four in this example)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the difference shows up
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Human tasks and permissions
&lt;/h3&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;In Elsa, &lt;code&gt;RunTask&lt;/code&gt; 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 &lt;a href="https://workflowengine.io/blog/elsa-vs-workflow-engine/#approval-process" rel="noopener noreferrer"&gt;the application integration for both engines&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  A decision and a deadline at the same moment
&lt;/h3&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;In Elsa, &lt;code&gt;Fork(WaitAny)&lt;/code&gt; 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. &lt;a href="https://workflowengine.io/blog/elsa-vs-workflow-engine/#concurrency-locking" rel="noopener noreferrer"&gt;Concurrent events and process locking&lt;/a&gt; walks through the race in both engines.&lt;/p&gt;

&lt;h3&gt;
  
  
  Timers on more than one node
&lt;/h3&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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 &lt;a href="https://workflowengine.io/blog/elsa-vs-workflow-engine/#durable-waits" rel="noopener noreferrer"&gt;long-running waits in both engines&lt;/a&gt; links the Elsa documentation and scheduler source behind these points.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tenants
&lt;/h3&gt;

&lt;p&gt;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 &lt;code&gt;Workflow-Api-Tenant-ID&lt;/code&gt; header and routes the request to that tenant's runtime and database. Its tenant scope covers the Inbox, forms, timers, history and permissions.&lt;/p&gt;

&lt;p&gt;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. &lt;a href="https://workflowengine.io/blog/elsa-vs-workflow-engine/#multitenancy" rel="noopener noreferrer"&gt;Multitenancy architecture in both engines&lt;/a&gt; compares the storage models in one diagram.&lt;/p&gt;

&lt;h3&gt;
  
  
  The editor in your frontend
&lt;/h3&gt;

&lt;p&gt;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 &lt;a href="https://workflowengine.io/blog/elsa-vs-workflow-engine/#visual-designer" rel="noopener noreferrer"&gt;visual authoring and editor embedding&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  When I would choose Elsa
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Event and integration pipelines.&lt;/strong&gt; Triggers and bookmarks, HTTP and MassTransit activities, dispatch, child workflows and parallel branches are Elsa's native model.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code-first workflows owned by developers.&lt;/strong&gt; &lt;code&gt;WorkflowBase&lt;/code&gt; keeps 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.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Calls to models and tools.&lt;/strong&gt; The optional Elsa Agents extension turns configured agents into activities and selected skills into functions a model can call.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open source as a hard requirement.&lt;/strong&gt; Elsa Core, Elsa Studio and Elsa's extensions use the MIT license, so you can modify and redistribute them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Elsa can also cost less when your product already has the task, forms and operations pieces around it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the license pays for
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/elsa-workflows/elsa-core" rel="noopener noreferrer"&gt;Elsa Core&lt;/a&gt; is MIT and has no runtime license fee. Paid support and services come from independent providers listed on &lt;a href="https://www.elsaworkflows.io/elsa-plus" rel="noopener noreferrer"&gt;Elsa+&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The editions and prices of Workflow Engine NEO are on the &lt;a href="https://workflowengine.io/pricing/" rel="noopener noreferrer"&gt;pricing page&lt;/a&gt;. 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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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 &lt;a href="https://workflowengine.io/blog/elsa-vs-workflow-engine/#licensing" rel="noopener noreferrer"&gt;licensing and total cost&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test both before you choose
&lt;/h2&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;For the Workflow Engine NEO side, request a &lt;a href="https://trial.workflowengine.io/" rel="noopener noreferrer"&gt;30-day trial key&lt;/a&gt;. If you compare engines with an AI assistant, give it the &lt;a href="https://workflowengine.io/blog/elsa-vs-workflow-engine/index.md" rel="noopener noreferrer"&gt;Markdown version of the full comparison&lt;/a&gt;, so it works from the same text you read.&lt;/p&gt;

&lt;p&gt;If I read Elsa's documentation wrong anywhere, say so in the comments or in &lt;a href="https://github.com/optimajet/WorkflowEngine.NET/discussions" rel="noopener noreferrer"&gt;GitHub Discussions&lt;/a&gt;, and I will change the row in the full comparison. If you would rather see this against your own process, &lt;a href="https://workflowengine.io/book-a-demo/" rel="noopener noreferrer"&gt;book a call&lt;/a&gt;. I am the person on the other side of it.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>architecture</category>
      <category>saas</category>
    </item>
    <item>
      <title>Workflow Engine by Optimajet is now a family of four products</title>
      <dc:creator>Optimajet Limited</dc:creator>
      <pubDate>Fri, 25 Sep 2026 15:52:18 +0000</pubDate>
      <link>https://dev.to/optimajet/workflow-engine-by-optimajet-is-now-a-family-of-four-products-3611</link>
      <guid>https://dev.to/optimajet/workflow-engine-by-optimajet-is-now-a-family-of-four-products-3611</guid>
      <description>&lt;p&gt;One workflow engine for every .NET scenario, as an embeddable library, an HTTP API or a standalone server, now in four products with a new website.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Key takeaways&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The Workflow Engine Family by Optimajet is one .NET workflow engine in four products: Workflow Engine Free and Workflow Engine as an embeddable library, Workflow Engine NEO as an HTTP API, and Workflow Server as a standalone server. A scheme drawn in Workflow Designer or built in C# runs in all four.&lt;/li&gt;
&lt;li&gt;Workflow Engine NEO is the flagship, for teams whose workflows are part of the product they sell. Workflow Engine NEO adds the Data API and RPC API groups of Workflow Engine HTTP API and ready multitenancy. A 30-day trial key from trial.workflowengine.io lets a team try Workflow Engine NEO on its own process before buying.&lt;/li&gt;
&lt;li&gt;Every edition of Workflow Engine NEO includes Workflow Forms for human tasks. The Forms Plugin behind Workflow Forms integrates Form Engine, Optimajet's separate form product family, and shows each person only the forms whose commands they may run.&lt;/li&gt;
&lt;li&gt;Workflow Engine Free, formerly Community Edition, is for personal, non-commercial use, needs no license key and allows 10 schemes and 4 execution threads.&lt;/li&gt;
&lt;li&gt;Workflow Engine, Workflow Engine NEO and Workflow Server are source-available under a commercial EULA, and Workflow Engine Free is not. Engine source access is a one-year window, included with NEO Enterprise and an add-on for Workflow Engine Complete, NEO Business and NEO SaaS. Workflow Server source comes with Business Ultimate and Custom.&lt;/li&gt;
&lt;li&gt;The engine has shipped inside commercial .NET products since 2014. The current release is 22.1.0, from August 2026, and its core library targets .NET Standard 2.0, supported on .NET 8, .NET 10 and .NET Framework 4.6.2.&lt;/li&gt;
&lt;li&gt;The new workflowengine.io went live on September 22, 2026, with a comparison of the four products at workflowengine.io/products/compare/ and new documentation at docs.workflowengine.io. For existing users, the NuGet packages and their names, license keys and schemes stay the same.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;The Optimajet team and I are proud of the work behind this launch. Since 2014, .NET teams have built Workflow Engine into CRM, ERP and HR systems, and into software that manages documents. Over those years, four products grew around the engine, and it was not always easy to see which one you needed. This launch fixes that. For .NET developers and teams, the product line is now more useful and easier to work with. The engine your applications run has not changed.&lt;/p&gt;

&lt;p&gt;Thank you to every team that uses our products and tells us which features matter most to them and what they need next. We are especially grateful to Acer, AMCS Group, Avery Dennison, Conduent, Consolsys, DigiNation, Elm Company, EY (formerly Ernst &amp;amp; Young), Fiserv, Ideagen EHS (formerly ProcessMAP), Indra, KARL STORZ, Leah (formerly ContractPodAi), Ncontracts and Novartis. Their feedback shapes the features we build, and it makes each proof of concept with a new customer better. We could not have improved these products without them.&lt;/p&gt;

&lt;p&gt;The four products share &lt;a href="https://workflowengine.io/" rel="noopener noreferrer"&gt;one workflow engine&lt;/a&gt;, and the schemes that describe your processes carry over when you switch between them. A new website went live on September 22, 2026, together with &lt;a href="https://docs.workflowengine.io/" rel="noopener noreferrer"&gt;new documentation&lt;/a&gt;, and both are built to help you choose. Workflow Engine NEO is the flagship, built for teams whose workflows are part of the product they sell.&lt;/p&gt;

&lt;h2&gt;
  
  
  One workflow engine for every .NET scenario
&lt;/h2&gt;

&lt;p&gt;The four products run the same engine in three ways. They differ in where it runs, how your application calls it and what the license includes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;As an embeddable library.&lt;/strong&gt; &lt;a href="https://workflowengine.io/products/community-edition/" rel="noopener noreferrer"&gt;Workflow Engine Free&lt;/a&gt; and &lt;a href="https://workflowengine.io/products/dotnet-workflow-engine/" rel="noopener noreferrer"&gt;Workflow Engine&lt;/a&gt; run inside your .NET application, and you call them from C#. They use the same NuGet packages. Workflow Engine Free is for personal, non-commercial use and needs no license key. It allows 10 schemes and 4 execution threads, the number of processes the engine advances at the same time. Workflow Engine is licensed for internal commercial applications, in two editions, Team and Complete.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;As an HTTP API.&lt;/strong&gt; &lt;a href="https://workflowengine.io/products/workflow-engine-neo/" rel="noopener noreferrer"&gt;Workflow Engine NEO&lt;/a&gt;, the flagship, is a separate product based on Workflow Engine. It adds the Data API and RPC API groups of Workflow Engine HTTP API and ready multitenancy to your application. A web front end, a mobile app or another service can then drive your processes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;As a standalone server.&lt;/strong&gt; &lt;a href="https://workflowengine.io/products/workflow-server/" rel="noopener noreferrer"&gt;Workflow Server&lt;/a&gt; is a separate service you run in Docker. Any language can call it over HTTP.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All four run on your own infrastructure, and none of them is a hosted Optimajet service. The embeddable products keep process data in your database: SQL Server, PostgreSQL, MySQL, Oracle, MongoDB or SQLite.&lt;/p&gt;

&lt;h2&gt;
  
  
  Workflow Engine NEO is the flagship
&lt;/h2&gt;

&lt;p&gt;Workflow Engine NEO is a separate product in the Workflow Engine Family. It is based on Workflow Engine, but it is not an edition of Workflow Engine. Its editions are Subscription, Business, SaaS and Enterprise. It is built for teams whose workflows are part of the product they sell. Typical products are a CRM, an ERP, an HR system or a document management platform.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Data API and RPC API.&lt;/strong&gt; The &lt;a href="https://docs.workflowengine.io/evaluate/workflow-engine-features/http-api/" rel="noopener noreferrer"&gt;OptimaJet.Workflow.Api&lt;/a&gt; package adds Workflow Engine HTTP API to your ASP.NET Core application. Without a NEO key it serves the Designer API and the Health Check API. With one, it also serves the Data API and the RPC API. The Data API reads and changes schemes, process instances, parameters, timers and approvals, with search, filtering and paging. The RPC API runs the engine, for example to create a process instance, execute a command or list the commands available now.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://workflowengine.io/features/multi-tenancy/" rel="noopener noreferrer"&gt;Multitenancy&lt;/a&gt;.&lt;/strong&gt; One deployment serves many customers. The HTTP API applies the tenant to every built-in operation. Each tenant can live in shared storage, its own database or its own database schema, and one deployment can mix all three. In Workflow Engine, your code builds that isolation around a tenant ID.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security.&lt;/strong&gt; The HTTP API uses your application's ASP.NET Core authentication, such as JWT bearer tokens or cookies. Each operation has its own &lt;code&gt;OperationId&lt;/code&gt;, and &lt;code&gt;IWorkflowApiPermissions&lt;/code&gt; decides who may call it. The tenant header only selects the tenant. Whether the caller may use that tenant is a separate permission check, which you enable with API security. Your own endpoints stay your responsibility.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scale.&lt;/strong&gt; Every edition of Workflow Engine NEO runs on multiple servers. In Workflow Engine, multi-server needs the Complete edition, and Team runs on one server.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://workflowengine.io/features/workflow-forms/" rel="noopener noreferrer"&gt;Workflow Forms&lt;/a&gt; for human tasks.&lt;/strong&gt; Every edition of Workflow Engine NEO includes the Forms Plugin, installed as the &lt;a href="https://www.nuget.org/packages/WorkflowEngine.NETCore-FormsPlugin/" rel="noopener noreferrer"&gt;WorkflowEngine.NETCore-FormsPlugin&lt;/a&gt; package. In Workflow Engine it is an add-on for Complete and is not available on Team. It binds a form to a workflow step and shows each person only the forms whose commands they may run. Submitting a form runs that command, and the workflow's restrictions are checked again. A tenant can have its own version of a form, with the shared one as the fallback.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Forms from &lt;a href="https://formengine.io/" rel="noopener noreferrer"&gt;Form Engine&lt;/a&gt;.&lt;/strong&gt; The Forms Plugin integrates Form Engine, Optimajet's separate form product family. Form Engine Core renders the forms under the &lt;a href="https://www.npmjs.com/package/@react-form-builder/core" rel="noopener noreferrer"&gt;MIT license&lt;/a&gt;, and Form Engine Designer lets an analyst lay out a form without a frontend ticket. Workflow Engine NEO Enterprise includes the Form Engine Enterprise license, which covers the Designer, with OEM rights. On the other editions, that license is priced separately.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The right to ship.&lt;/strong&gt; The Subscription and SaaS editions cover a public web app or SaaS, and the Enterprise edition adds OEM distribution. The &lt;a href="https://workflowengine.io/pricing/" rel="noopener noreferrer"&gt;pricing page&lt;/a&gt; states the licensed use of every edition.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In our &lt;a href="https://workflowengine.io/blog/elsa-vs-workflow-engine/" rel="noopener noreferrer"&gt;comparison with Elsa Workflows&lt;/a&gt;, Workflow Engine NEO supplied the commands, permission checks, inbox and forms for one approval process. Elsa needed an external task-and-forms layer for the same process.&lt;/p&gt;

&lt;p&gt;To evaluate Workflow Engine NEO, request a &lt;a href="https://trial.workflowengine.io/" rel="noopener noreferrer"&gt;30-day trial key&lt;/a&gt;. The key enables its licensed capabilities. Your team can then run the Data API, the RPC API and multitenancy on a process of its own before you buy. A one-hour &lt;a href="https://workflowengine.io/book-a-demo/" rel="noopener noreferrer"&gt;demo&lt;/a&gt; walks through your case with us. For more depth, read &lt;a href="https://workflowengine.io/blog/data-api-vs-rpc-api-in-workflow-engine-neo/" rel="noopener noreferrer"&gt;Data API or RPC API, which one your caller needs&lt;/a&gt; and &lt;a href="https://workflowengine.io/blog/workflow-engine-neo-22-0-0-dynamic-tenant-registration/" rel="noopener noreferrer"&gt;dynamic tenant registration in NEO 22.0.0&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  One scheme runs in all four products
&lt;/h2&gt;

&lt;p&gt;A scheme is the workflow definition you draw in Workflow Designer or build in C#. It runs in all four products, and schemes written for older versions still run on the current release. That is what makes the four products one family, and it makes the choice above safe to make early. Scheme compatibility is separate from upgrading the application. The runtime, the packages and the database follow the &lt;a href="https://workflowengine.io/documentation/release-notes/" rel="noopener noreferrer"&gt;release notes&lt;/a&gt;, and 22.0.0, for example, required database migrations.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;From Workflow Engine Free to Workflow Engine, you register a license key. The packages stay the same, and the key lifts the limits.&lt;/li&gt;
&lt;li&gt;From Workflow Engine to Workflow Engine NEO, the switch itself is a license key. The existing application and its schemes keep running as they are, on the same version. Using the Data API, the RPC API and multitenancy is planned work. You add the packages, configure authentication and tenants, and write the code that calls them.&lt;/li&gt;
&lt;li&gt;Workflow Server runs as a separate service, so moving to it changes how you deploy. Your schemes still carry over.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Source access and vendor lock-in
&lt;/h2&gt;

&lt;p&gt;The first objection to a commercial engine is lock-in, because your product depends on code you cannot see. Three of the four products answer it. Workflow Engine, Workflow Engine NEO and Workflow Server are source-available, under a commercial EULA, and Workflow Engine Free is the one product without source access.&lt;/p&gt;

&lt;p&gt;For Workflow Engine and Workflow Engine NEO, source access is a one-year window on GitHub to the full engine source, as is, to read and review. It is included with Workflow Engine NEO Enterprise and is an add-on for Workflow Engine Complete, NEO Business and NEO SaaS. Team and NEO Subscription do not include it. Workflow Server includes its full source for one year with the Business Ultimate and Custom editions.&lt;/p&gt;

&lt;p&gt;Source access is one of several guards against lock-in. Every edition of Workflow Engine and Workflow Engine NEO except NEO Subscription is a perpetual license, so the version you bought keeps running. A lapsed NEO Subscription falls back to the Workflow Engine Free limits. The engine runs on your infrastructure and keeps process data in your own database. Your schemes carry over between the four products, and there are no royalties or per-execution fees. The &lt;a href="https://workflowengine.io/pricing/" rel="noopener noreferrer"&gt;pricing page&lt;/a&gt; shows the source access, license model and support of every edition.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changed, and what did not
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What is new
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;One product family, the Workflow Engine Family, and one &lt;a href="https://workflowengine.io/products/compare/" rel="noopener noreferrer"&gt;comparison page&lt;/a&gt; for its four products.&lt;/li&gt;
&lt;li&gt;A new website at workflowengine.io, with a page for each product and public prices for Workflow Engine and Workflow Engine NEO.&lt;/li&gt;
&lt;li&gt;New documentation at docs.workflowengine.io, which starts with Evaluate and Get Started and defines every term in a Glossary.&lt;/li&gt;
&lt;li&gt;Clear lines between products and editions, including source-code access and what needs a paid edition or an add-on.&lt;/li&gt;
&lt;li&gt;A new name for the free product, Workflow Engine Free, formerly Community Edition.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What stays the same
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;The NuGet packages and their names.&lt;/li&gt;
&lt;li&gt;The license keys you already have.&lt;/li&gt;
&lt;li&gt;Your schemes, including those written for older versions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Compare the four products row by row
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://workflowengine.io/products/compare/" rel="noopener noreferrer"&gt;comparison of Workflow Engine products&lt;/a&gt; is the page to open before any other. It sets all four side by side, one capability per row, from durable execution and Workflow Designer to APIs, databases, multitenancy, scaling and licensing. Where the answer depends on the edition or an add-on, the cell names it. The Forms Plugin row, for example, reads "Not available" for the Team edition and "Add-on" for Complete. Every edition of Workflow Engine NEO includes it.&lt;/p&gt;

&lt;p&gt;Row names link to the pages that document each capability, and the common questions are answered below the table. The same matrix is published as Markdown at &lt;a href="https://workflowengine.io/products/compare/index.md" rel="noopener noreferrer"&gt;workflowengine.io/products/compare/index.md&lt;/a&gt;. When you ask an AI assistant which of our products fits your case, give it that link. It can then answer from the same table you would read.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why we rebuilt the site and the documentation
&lt;/h2&gt;

&lt;p&gt;As the family grew, the old site no longer matched the way customers evaluate our products. Workflow Engine NEO had no page of its own, and the prices were on optimajet.com, a different site. The free product's old name also read like an edition of the paid library.&lt;/p&gt;

&lt;p&gt;The new site starts from the choice. The comparison page answers what each product includes, the pricing page what it costs, and the documentation how it works.&lt;/p&gt;

&lt;p&gt;The documentation starts one step earlier too, with &lt;a href="https://docs.workflowengine.io/evaluate/" rel="noopener noreferrer"&gt;Evaluate&lt;/a&gt; for the choice and &lt;a href="https://docs.workflowengine.io/get-started/" rel="noopener noreferrer"&gt;Get Started&lt;/a&gt; for a first running process in about 15 minutes. The &lt;a href="https://docs.workflowengine.io/glossary/" rel="noopener noreferrer"&gt;Glossary&lt;/a&gt; defines each product, edition and term once.&lt;/p&gt;

&lt;p&gt;The new documentation is marked as a preview while its last pages are written, and both documentation hosts are official. The &lt;a href="https://workflowengine.io/documentation/" rel="noopener noreferrer"&gt;previous documentation&lt;/a&gt; still holds the release notes, the setup and security of the HTTP API, and the BPMN and database reference tables.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where each answer lives
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://workflowengine.io/pricing/" rel="noopener noreferrer"&gt;Workflow Engine pricing&lt;/a&gt; gives the price, license model, licensed use, limits, source-code access and support of every edition of Workflow Engine and Workflow Engine NEO. Every price is public except Workflow Engine NEO Enterprise, which we quote per project.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://workflowengine.io/enterprise/" rel="noopener noreferrer"&gt;Enterprise support and security&lt;/a&gt; covers self-hosting inside your perimeter, security questionnaires and support plans with a committed response time. Tickets go to the engineers who own the codebase.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://workflowengine.io/features/" rel="noopener noreferrer"&gt;Workflow Engine features&lt;/a&gt; lists every feature in the documentation's catalog, each with one sentence and a link. Full pages with code and limits cover &lt;a href="https://workflowengine.io/features/workflow-designer/" rel="noopener noreferrer"&gt;Workflow Designer&lt;/a&gt;, &lt;a href="https://workflowengine.io/features/bpmn/" rel="noopener noreferrer"&gt;BPMN support&lt;/a&gt;, &lt;a href="https://workflowengine.io/features/multi-tenancy/" rel="noopener noreferrer"&gt;multi-tenant workflow architecture&lt;/a&gt;, &lt;a href="https://workflowengine.io/features/workflow-forms/" rel="noopener noreferrer"&gt;Workflow Forms&lt;/a&gt;, &lt;a href="https://workflowengine.io/features/multi-database/" rel="noopener noreferrer"&gt;database providers&lt;/a&gt;, the &lt;a href="https://workflowengine.io/features/plugin-system/" rel="noopener noreferrer"&gt;plugin system&lt;/a&gt; and &lt;a href="https://workflowengine.io/features/pluggable-security/" rel="noopener noreferrer"&gt;LDAP and Active Directory authorization&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Workflow Designer also has pages for &lt;a href="https://workflowengine.io/features/blazor-workflow-designer/" rel="noopener noreferrer"&gt;Blazor&lt;/a&gt;, &lt;a href="https://workflowengine.io/features/javascript-workflow-designer/" rel="noopener noreferrer"&gt;JavaScript&lt;/a&gt; and &lt;a href="https://workflowengine.io/features/react-workflow-designer/" rel="noopener noreferrer"&gt;React&lt;/a&gt;. The code on them ran on version 22.1.0. Each page has a prompt you can paste into Cursor, Claude Code or Copilot. The agent reads the page as Markdown before it changes your app.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://workflowengine.io/blog/elsa-vs-workflow-engine/" rel="noopener noreferrer"&gt;Elsa Workflows vs Workflow Engine NEO&lt;/a&gt; builds the same approval process in both engines and says where each one fits.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://workflowengine.io/blog/workflow-engine-for-ehs-management-software/" rel="noopener noreferrer"&gt;How ProcessMAP runs EHS workflows on Workflow Engine&lt;/a&gt; shows the engine inside a commercial SaaS platform for environment, health and safety.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Written for AI assistants as well
&lt;/h2&gt;

&lt;p&gt;You may ask an AI assistant about a library before you open its website, so the site gives that assistant pages it can read. The &lt;a href="https://workflowengine.io/llms.txt" rel="noopener noreferrer"&gt;llms.txt&lt;/a&gt; file is a short map of workflowengine.io for AI tools, and &lt;a href="https://workflowengine.io/llms-full.txt" rel="noopener noreferrer"&gt;llms-full.txt&lt;/a&gt; is the full product reference in one file. Both point an assistant to the Markdown copies of the comparison page, the pricing page, the Workflow Designer guides and the Elsa comparison. Every post in &lt;a href="https://workflowengine.io/blog/" rel="noopener noreferrer"&gt;our blog&lt;/a&gt; has a Markdown copy and a Copy page button. Each documentation page can be copied as Markdown or opened in ChatGPT or Claude.&lt;/p&gt;

&lt;p&gt;A coding agent can also request a 30-day trial key for you through &lt;a href="https://trial.workflowengine.io/llms.txt" rel="noopener noreferrer"&gt;trial.workflowengine.io/llms.txt&lt;/a&gt;. The request carries your business email and company name, so the agent should ask you first.&lt;/p&gt;

&lt;p&gt;If something you used on the old site is missing, tell us in &lt;a href="https://github.com/optimajet/WorkflowEngine.NET/discussions" rel="noopener noreferrer"&gt;GitHub Discussions&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Which Workflow Engine product do I need?
&lt;/h3&gt;

&lt;p&gt;It depends on how you run the engine. For a library you call from C# inside a .NET application, use Workflow Engine, or Workflow Engine Free for personal, non-commercial use. For an HTTP API that a web front end, a mobile app or another service calls, use Workflow Engine NEO. It is also the choice when you serve many tenants. For a separate service in Docker that any language can call, use Workflow Server.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is Workflow Engine open source?
&lt;/h3&gt;

&lt;p&gt;No. Workflow Engine by Optimajet is commercial software with a free product, Workflow Engine Free, for personal, non-commercial use. Workflow Engine, Workflow Engine NEO and Workflow Server are source-available, with full source access in selected editions under a commercial EULA. Workflow Engine Free is the one product without source access.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do I evaluate Workflow Engine NEO?
&lt;/h3&gt;

&lt;p&gt;Request a 30-day trial key at trial.workflowengine.io. The key enables the licensed capabilities, including the Data API, the RPC API and multitenancy, so your team can test them on its own process. A coding agent can request the key for you through trial.workflowengine.io/llms.txt once you agree to share your business email and company name. A one-hour demo walks through your case with our team.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does Workflow Engine NEO include forms for human tasks?
&lt;/h3&gt;

&lt;p&gt;Yes. Every edition of Workflow Engine NEO includes the Forms Plugin, the component behind Workflow Forms. It binds a form to a workflow step and shows each person only the forms whose commands they may run. On submit it runs the command and checks the workflow's restrictions again. The Forms Plugin integrates Form Engine. Form Engine Core renders the forms under the MIT license, and Workflow Engine NEO Enterprise includes the Form Engine Enterprise license, which covers Form Engine Designer, with OEM rights.&lt;/p&gt;

&lt;h3&gt;
  
  
  What changed for existing Workflow Engine users?
&lt;/h3&gt;

&lt;p&gt;Nothing in the product changed with the launch. The engine, the NuGet packages, your license keys and your schemes work as before, and the current release is 22.1.0. What is new is the family of four products, the comparison page, the website and the documentation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I use Workflow Engine in software I sell to my customers?
&lt;/h3&gt;

&lt;p&gt;Yes, with the right edition. Workflow Engine Team and Complete cover internal commercial applications. A public web app or SaaS needs the Subscription, SaaS or Enterprise edition of Workflow Engine NEO, and OEM distribution needs Workflow Engine NEO Enterprise.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is Workflow Engine NEO a cloud service?
&lt;/h3&gt;

&lt;p&gt;No. Workflow Engine NEO is software you run on your own infrastructure, like the other three products. The name of its SaaS edition describes your application, not a service that Optimajet hosts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where can I compare Workflow Engine products?
&lt;/h3&gt;

&lt;p&gt;Use the comparison page at workflowengine.io/products/compare/. It sets Workflow Engine Free, Workflow Engine, Workflow Engine NEO and Workflow Server side by side, one capability per row. Where the answer depends on the edition or an add-on, the cell names it. A Markdown copy for AI assistants is at workflowengine.io/products/compare/index.md.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is Workflow Engine Free an edition of Workflow Engine?
&lt;/h3&gt;

&lt;p&gt;No. Workflow Engine Free is a separate product for personal, non-commercial use, and it needs no license key. It uses the same library as Workflow Engine, limited to 10 schemes and 4 execution threads. A Workflow Engine license key lifts those limits, and the packages stay the same.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I move an application from Workflow Engine to Workflow Engine NEO?
&lt;/h3&gt;

&lt;p&gt;Yes. Register a Workflow Engine NEO license key, and the application keeps running as before, on the same version. To use the Data API, the RPC API and multitenancy, you add the packages, configure authentication and tenants, and write the code that calls them. Your schemes carry over, as they do between all four products.&lt;/p&gt;

&lt;h3&gt;
  
  
  Where is the previous Workflow Engine documentation?
&lt;/h3&gt;

&lt;p&gt;It stays online at workflowengine.io/documentation/ while the new documentation at docs.workflowengine.io is in preview. Release notes, setup and security of the HTTP API, and the BPMN and database reference tables are still there.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with Workflow Engine NEO
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://workflowengine.io/products/workflow-engine-neo/" rel="noopener noreferrer"&gt;Its page&lt;/a&gt; shows what the Data API, the RPC API, multitenancy and the Forms Plugin add. &lt;a href="https://workflowengine.io/products/compare/" rel="noopener noreferrer"&gt;Compare it with the other three products&lt;/a&gt;, and &lt;a href="https://workflowengine.io/book-a-demo/" rel="noopener noreferrer"&gt;book a demo&lt;/a&gt; when you want to walk through your case with us.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>workflow</category>
      <category>documentation</category>
    </item>
    <item>
      <title>Your coding agent can now write a .NET workflow engine integration</title>
      <dc:creator>Optimajet Limited</dc:creator>
      <pubDate>Wed, 29 Jul 2026 19:34:17 +0000</pubDate>
      <link>https://dev.to/optimajet/your-coding-agent-can-now-write-a-net-workflow-engine-integration-2lkb</link>
      <guid>https://dev.to/optimajet/your-coding-agent-can-now-write-a-net-workflow-engine-integration-2lkb</guid>
      <description>&lt;p&gt;Ask Codex, Claude or Cursor to wire a workflow library into a .NET service and you usually get code that looks right and calls a method that doesn't exist. Say the agent gets past that. It then hits the line "obtain a license key from the vendor" and stops, because that step was built for a human with a browser and an email inbox.&lt;/p&gt;

&lt;p&gt;I work on Workflow Engine at Optimajet, and we've recently rebuilt our documentation. The new primary documentation is available at &lt;a href="https://docs.workflowengine.io/" rel="noopener noreferrer"&gt;docs.workflowengine.io&lt;/a&gt;. It is gradually replacing the legacy documentation at &lt;a href="https://workflowengine.io/documentation/" rel="noopener noreferrer"&gt;workflowengine.io/documentation&lt;/a&gt;. It publishes its full text as a single file so an agent reads the whole thing in one request instead of guessing, and a trial key can now be obtained by an agent, without a human clicking through a form.&lt;/p&gt;

&lt;p&gt;The rest is for humans: 57 pages, four sections, 24 feature pages, 17 pages that each define exactly one concept, plus the generated C# API reference on its own host, &lt;a href="https://api.workflowengine.io/" rel="noopener noreferrer"&gt;api.workflowengine.io&lt;/a&gt;, 1256 pages across 20 packages.&lt;/p&gt;

&lt;p&gt;If you've never touched the product: &lt;strong&gt;Workflow Engine by Optimajet&lt;/strong&gt; is an embeddable .NET library for workflow automation. You add a NuGet package to your app, point it at the database you already have, and it handles process state, transitions, timers, rules and actions in-process. Nothing extra to deploy, no separate workflow server to babysit. It works on .NET Framework 4.6.2 and up as well as modern .NET and ASP.NET Core, and it persists to SQL Server (2017+), PostgreSQL, MySQL, Oracle, SQLite or MongoDB, whichever provider package you install.&lt;/p&gt;

&lt;p&gt;A quick note before anyone asks: Workflow Engine is commercial software with a free tier. It's not open source, but Enterprise customers can obtain the full source code as part of their license. We've been shipping it since 2014. The latest stable release is 22.0.0, released on July 16, 2026.&lt;/p&gt;

&lt;h2&gt;
  
  
  Two text files and a key
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.workflowengine.io/llms.txt" rel="noopener noreferrer"&gt;&lt;code&gt;llms.txt&lt;/code&gt;&lt;/a&gt; is the index, every published page with a one-line description, about 11 KB. &lt;a href="https://docs.workflowengine.io/llms-full.txt" rel="noopener noreferrer"&gt;&lt;code&gt;llms-full.txt&lt;/code&gt;&lt;/a&gt; is the full text of every page with its source URL attached, about 480 KB. One fetch gives an agent the complete documentation corpus together with source URLs, making it easier to reference documented APIs instead of inferring them.&lt;/p&gt;

&lt;p&gt;The key is the other half. &lt;code&gt;trial.workflowengine.io/llms.txt&lt;/code&gt; carries instructions an agent can follow to obtain a trial license key by itself. Writing correct integration code and then stalling on paperwork is a stupid way to lose an evaluation, and it was the failure we kept watching happen.&lt;/p&gt;

&lt;p&gt;The API reference host publishes an &lt;code&gt;llms.txt&lt;/code&gt; too. Bookmark &lt;a href="https://api.workflowengine.io/" rel="noopener noreferrer"&gt;api.workflowengine.io&lt;/a&gt;: it's the generated C# reference for all 20 packages (Core, six database providers, six plugins, the Migrator, and the Web API with its six provider packages). The main docs don't link to it yet, so browsing won't get you there. That one's on us, it's in the queue.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's actually on the site
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Section&lt;/th&gt;
&lt;th&gt;Pages&lt;/th&gt;
&lt;th&gt;What it's for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/evaluate/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;td&gt;Deciding. 24 feature pages, the edition list, licensing and trial keys.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/get-started/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;24&lt;/td&gt;
&lt;td&gt;Running it. Install, first workflow, designer integration, 17 concept pages.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/roadmap/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;What's next.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;/video-tutorials/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;For people who'd rather watch.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The feature pages are one page per capability, named the way the product names them: Visual Designer, Simple Process Notation, Process Versioning, Parallel Processes, Timers &amp;amp; Scheduling, Direct State Control, HTTP API, BPMN Support, Plugin System, Pluggable Security, Clustering, Multitenancy, Attachable Forms, Customization, Multi-Database Support, Bulk API, Work Calendar, Pre-Execution (Simulation), Process Logs, Workflow as Code, Database Versioning, Offline API, Interactive Designer, Workflow Templates.&lt;/p&gt;

&lt;p&gt;The concept pages were the ones I most wanted to exist. Seventeen terms, one page each, no page trying to explain four things at once: activity, transition, command, scheme, process instance, workflow runtime, persistence, action, parameter, condition, rule, timer, annotation, process logs, localization, subprocess, work calendar. Workflow tools all use the same handful of words to mean slightly different things, and a shared vocabulary saves a lot of arguing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Fifteen minutes, roughly
&lt;/h2&gt;

&lt;p&gt;Get Started is three short pages: install, define a scheme, start an instance. Here's the shape of it, with SQLite because it doesn't need a server running.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet new webapi &lt;span class="nt"&gt;-n&lt;/span&gt; WorkflowApi &lt;span class="nt"&gt;--framework&lt;/span&gt; net10.0
&lt;span class="nb"&gt;cd &lt;/span&gt;WorkflowApi
dotnet add package OptimaJet.Workflow.Api
dotnet add package OptimaJet.Workflow.Api.Sqlite
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Register the services and map the endpoints:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;WebApplication&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddControllers&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;AddJsonOptions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ConfigureJson&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddWorkflowApiSqlite&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddWorkflowApiCore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SetupWorkflowApiCore&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddWorkflowRuntime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SetupWorkflowRuntime&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Build&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;UseRouting&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;MapWorkflowApi&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can write the scheme as XML, or draw it in the designer without installing the designer at all:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx @optimajet/workflow-designer http://localhost:5274/workflow-api/designer Approval
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That opens the full designer in a browser tab, wired to your local Web API. Save from there and the scheme goes into your database. Then start a process instance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST http://localhost:5274/workflow-api/rpc/create-instance &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{ "schemeCode": "Approval", "processId": "a3f5b2c1-4d6e-7f8a-9b0c-1d2e3f4a5b6c" }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You need the .NET SDK 10.0 and a database for that path, and SQLite counts, it's just a file. Console apps and worker services have their own page, &lt;a href="https://docs.workflowengine.io/get-started/framework-agnostic-install/" rel="noopener noreferrer"&gt;Framework-Agnostic Install&lt;/a&gt;. We didn't want ASP.NET Core to be a precondition for trying the library.&lt;/p&gt;

&lt;h2&gt;
  
  
  Editions
&lt;/h2&gt;

&lt;p&gt;The license key you pass to &lt;code&gt;WorkflowRuntime.RegisterLicense()&lt;/code&gt; decides which edition you're running. Same package either way, so moving up a tier is a key swap, not a rewrite.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Edition&lt;/th&gt;
&lt;th&gt;License&lt;/th&gt;
&lt;th&gt;Limits and additions&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Workflow Engine Free&lt;/td&gt;
&lt;td&gt;Perpetual, personal and non-commercial&lt;/td&gt;
&lt;td&gt;10 schemas, 4 execution threads, unlimited activities, transitions and commands, Optimajet branding in the designer, no key needed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Workflow Engine Team&lt;/td&gt;
&lt;td&gt;Perpetual, internal commercial use&lt;/td&gt;
&lt;td&gt;No schema limit, higher thread and command limits, single server, 365 days of updates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Workflow Engine Complete&lt;/td&gt;
&lt;td&gt;Perpetual, internal commercial use&lt;/td&gt;
&lt;td&gt;No usage limits, multi-server clustering, no designer branding&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Workflow Engine NEO&lt;/td&gt;
&lt;td&gt;Annual subscription&lt;/td&gt;
&lt;td&gt;RPC and REST API, full hybrid multitenancy, clustering, forms integration&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Workflow Engine NEO Business&lt;/td&gt;
&lt;td&gt;Perpetual&lt;/td&gt;
&lt;td&gt;NEO APIs, clustering, forms, without full hybrid multitenancy&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Workflow Engine NEO SaaS&lt;/td&gt;
&lt;td&gt;Perpetual&lt;/td&gt;
&lt;td&gt;Full NEO set, plus Active Directory connector and BPMN import&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Workflow Engine NEO Enterprise&lt;/td&gt;
&lt;td&gt;Perpetual&lt;/td&gt;
&lt;td&gt;All of the above, plus white-label canvas, OEM redistribution, the FormEngine React form builder, one year of source code access&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Details are on &lt;a href="https://docs.workflowengine.io/evaluate/workflow-engine-editions/" rel="noopener noreferrer"&gt;Workflow Engine Editions&lt;/a&gt;, key mechanics on &lt;a href="https://docs.workflowengine.io/evaluate/license-key/" rel="noopener noreferrer"&gt;License Key&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Documentation status
&lt;/h2&gt;

&lt;p&gt;The documentation at &lt;strong&gt;docs.workflowengine.io&lt;/strong&gt; is the new primary documentation for Workflow Engine. It is intended to replace the legacy documentation hosted at &lt;strong&gt;workflowengine.io/documentation/&lt;/strong&gt; over time.&lt;/p&gt;

&lt;p&gt;The migration is still in progress. The new documentation already covers evaluation, installation, concepts, features, tutorials and API usage, but some reference material remains on the legacy site while it is being reviewed, updated and migrated.&lt;/p&gt;

&lt;p&gt;At the moment both documentation sites are maintained. If a topic cannot yet be found in the new documentation, the legacy documentation remains the authoritative source for that section until migration is complete.&lt;/p&gt;

&lt;h2&gt;
  
  
  What hasn't moved yet
&lt;/h2&gt;

&lt;p&gt;This is the section most docs announcements leave out, and it's the one that saves you a search.&lt;/p&gt;

&lt;p&gt;Still on the old host at &lt;code&gt;workflowengine.io/documentation/&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Web API setup and Web API security reference&lt;/li&gt;
&lt;li&gt;Release notes and version history&lt;/li&gt;
&lt;li&gt;BPMN element tables, BPMN differences, the BPMN plugin reference&lt;/li&gt;
&lt;li&gt;Database entity tables&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Those pages are alive and correct, they just haven't been rewritten for the new site. And Workflow Server, which is a different product with its own license, documents itself at &lt;a href="https://workflowserver.io/documentation/" rel="noopener noreferrer"&gt;workflowserver.io/documentation/&lt;/a&gt;. Don't go hunting for it under the engine docs, it isn't there.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where to go for what
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;You want&lt;/th&gt;
&lt;th&gt;Page&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Install into ASP.NET Core&lt;/td&gt;
&lt;td&gt;&lt;a href="https://docs.workflowengine.io/get-started/install-workflow-engine/" rel="noopener noreferrer"&gt;&lt;code&gt;/get-started/install-workflow-engine/&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Install into a console app or worker&lt;/td&gt;
&lt;td&gt;&lt;a href="https://docs.workflowengine.io/get-started/framework-agnostic-install/" rel="noopener noreferrer"&gt;&lt;code&gt;/get-started/framework-agnostic-install/&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Your first workflow&lt;/td&gt;
&lt;td&gt;&lt;a href="https://docs.workflowengine.io/get-started/create-your-first-workflow/" rel="noopener noreferrer"&gt;&lt;code&gt;/get-started/create-your-first-workflow/&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Run or embed the designer&lt;/td&gt;
&lt;td&gt;&lt;a href="https://docs.workflowengine.io/get-started/integrate-the-designer/" rel="noopener noreferrer"&gt;&lt;code&gt;/get-started/integrate-the-designer/&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A term you don't recognise&lt;/td&gt;
&lt;td&gt;&lt;a href="https://docs.workflowengine.io/get-started/concepts/workflow-engine-concepts/" rel="noopener noreferrer"&gt;&lt;code&gt;/get-started/concepts/&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;One feature in depth&lt;/td&gt;
&lt;td&gt;&lt;a href="https://docs.workflowengine.io/evaluate/workflow-engine-features/" rel="noopener noreferrer"&gt;&lt;code&gt;/evaluate/workflow-engine-features/&lt;/code&gt;&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A C# type or method signature&lt;/td&gt;
&lt;td&gt;&lt;a href="https://api.workflowengine.io/" rel="noopener noreferrer"&gt;api.workflowengine.io&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;A trial key&lt;/td&gt;
&lt;td&gt;&lt;a href="https://trial.workflowengine.io/" rel="noopener noreferrer"&gt;trial.workflowengine.io&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Questions we get
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What is Workflow Engine by Optimajet?&lt;/strong&gt;&lt;br&gt;
An embeddable .NET library for workflow automation. It's a NuGet package inside your application, using your database, running in-process. No separate workflow server.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is Workflow Engine open source?&lt;/strong&gt;&lt;br&gt;
No. Commercial software with a free tier, under a commercial license. Workflow Engine Free is perpetual and needs no key, but it's personal and non-commercial use only, capped at 10 schemas and 4 execution threads.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which databases does it support?&lt;/strong&gt;&lt;br&gt;
SQL Server 2017 and above, PostgreSQL, MySQL, Oracle, SQLite, MongoDB. You install the matching provider package and register it at startup.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which .NET versions?&lt;/strong&gt;&lt;br&gt;
.NET Framework 4.6.2 and up, plus modern .NET and ASP.NET Core. The ASP.NET Core quickstart targets the .NET SDK 10.0.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where is the documentation now?&lt;/strong&gt;&lt;br&gt;
Main docs at docs.workflowengine.io. Generated C# API reference at api.workflowengine.io. Web API setup and security, release notes, BPMN tables and database entity tables are still at workflowengine.io/documentation/. Workflow Server is at workflowserver.io/documentation/.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can an AI agent read the docs?&lt;/strong&gt;&lt;br&gt;
Yes, that's what &lt;code&gt;llms.txt&lt;/code&gt; and &lt;code&gt;llms-full.txt&lt;/code&gt; are for, and the API reference host has its own &lt;code&gt;llms.txt&lt;/code&gt;. An agent can also get a trial key by following &lt;code&gt;trial.workflowengine.io/llms.txt&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why not just write my own state machine?&lt;/strong&gt;&lt;br&gt;
Some teams should. The moment you need persistence, timers, rule evaluation, scheme versioning, clustering and a visual editor a business user can open, you're building a product next to your product. That's the trade we ask people to think about before adopting anything, ours included.&lt;/p&gt;

&lt;h2&gt;
  
  
  Go poke at it
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.workflowengine.io/get-started/" rel="noopener noreferrer"&gt;docs.workflowengine.io/get-started/&lt;/a&gt; if you want code in front of you in the next quarter of an hour. &lt;a href="https://docs.workflowengine.io/evaluate/" rel="noopener noreferrer"&gt;docs.workflowengine.io/evaluate/&lt;/a&gt; if you're still deciding whether an embedded engine beats rolling your own.&lt;/p&gt;

&lt;p&gt;And if a page is wrong, missing or confusing, tell me in the comments. I'd rather hear it here than not hear it at all.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>csharp</category>
      <category>documentation</category>
      <category>ai</category>
    </item>
    <item>
      <title>Workflow Engine NEO 22.0.0: the multitenancy questions SaaS teams should ask</title>
      <dc:creator>Optimajet Limited</dc:creator>
      <pubDate>Thu, 23 Jul 2026 12:04:16 +0000</pubDate>
      <link>https://dev.to/optimajet/multi-tenant-saas-on-a-net-workflow-engine-without-restarting-to-onboard-a-customer-h3a</link>
      <guid>https://dev.to/optimajet/multi-tenant-saas-on-a-net-workflow-engine-without-restarting-to-onboard-a-customer-h3a</guid>
      <description>&lt;p&gt;On July 16, 2026, we released &lt;a href="https://workflowengine.io/documentation/release-notes/22.0.0/" rel="noopener noreferrer"&gt;Workflow Engine NEO 22.0.0&lt;/a&gt;. Version 22 builds on the existing &lt;code&gt;TenantId&lt;/code&gt; and multi-tenant Web API support and addresses two harder problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a Workflow Engine Web API host can now add and remove tenant configurations while the application is running; and&lt;/li&gt;
&lt;li&gt;logical tenant scope now reaches workflow definitions, configuration, forms, processes, and process-related data more consistently.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Together, these changes complete support for physical, logical, and hybrid multitenancy in one Workflow Engine Web API host. A SaaS platform can give selected customers dedicated runtimes and databases, place others in logically isolated groups on shared infrastructure, and manage the entire topology through the same application. This flexibility is the central architectural capability in version 22.&lt;/p&gt;

&lt;p&gt;I am Mike Lukinov, co-founder of &lt;a href="https://optimajet.com/" rel="noopener noreferrer"&gt;Optimajet&lt;/a&gt;. This article explains how the three models fit together, then reviews the questions a SaaS team should answer before choosing its tenant architecture: where isolation lives, how tenants enter and leave the system, where authorization is enforced, what may be shared, and where product responsibilities split.&lt;/p&gt;

&lt;h2&gt;
  
  
  What hybrid multitenancy means
&lt;/h2&gt;

&lt;p&gt;Workflow Engine Web API separates physical and logical tenancy.&lt;/p&gt;

&lt;p&gt;A physical tenant is a runtime and provider boundary. It can use a dedicated database and can serve one or more logical tenant IDs. Logical tenants share that runtime and provider, while their workflow data is separated by &lt;code&gt;TenantId&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Hybrid multitenancy means using both mappings in one Web API host:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;One ASP.NET / Workflow Engine Web API host
|
|-- Physical tenant A
|   |-- Runtime and provider A
|   |-- Dedicated database A
|   `-- Logical tenant ID: acme
|
`-- Physical tenant B
    |-- Runtime and provider B
    |-- Shared database B
    `-- Logical tenant IDs: globex, stark
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Acme has its own runtime and database boundary. Globex and Stark share a runtime and database with logical separation. That combination is hybrid tenancy.&lt;/p&gt;

&lt;h2&gt;
  
  
  The five architecture questions
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Question&lt;/th&gt;
&lt;th&gt;Architecture decision&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Where should the isolation boundary sit?&lt;/td&gt;
&lt;td&gt;Shared database, dedicated database, or a combination of both.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Does onboarding require a deployment?&lt;/td&gt;
&lt;td&gt;Whether the tenant catalog belongs to application startup or to a runtime control plane.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Where is the security boundary?&lt;/td&gt;
&lt;td&gt;How identity, tenant authorization, routing, and persistence work together.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;What is isolated and what may be shared?&lt;/td&gt;
&lt;td&gt;Which data belongs exclusively to a tenant and which definitions act as common defaults.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Where does the engine's responsibility end?&lt;/td&gt;
&lt;td&gt;The boundary between Workflow Engine and the surrounding SaaS control plane.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Question 1: where should the isolation boundary sit?
&lt;/h2&gt;

&lt;p&gt;Workflow Engine NEO supports three answers.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Logical tenancy&lt;/strong&gt; puts several tenant IDs behind one runtime, provider, and database. It minimizes the number of infrastructure units while separating workflow data by tenant ID.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Physical tenancy&lt;/strong&gt; gives a tenant its own runtime and provider configuration. When its provider points to a dedicated database, it also creates an independent backup and restore boundary.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hybrid tenancy&lt;/strong&gt; uses physical isolation for customers that require it and logical isolation for customers that can share infrastructure.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The choice should follow operational requirements: data residency, regulatory commitments, independent backup and restore, database-provider requirements, and the acceptable impact of a database-level incident.&lt;/p&gt;

&lt;p&gt;A physical tenant remains part of the same ASP.NET application deployment. Its boundary covers runtime and persistence, while the application version and host process stay shared. Tenant-specific definitions also work in the logical model, allowing customized workflows to use shared infrastructure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Question 2: does onboarding require a deployment?
&lt;/h2&gt;

&lt;p&gt;Version 22.0.0 lets a multi-tenant host start with a partial tenant catalog and accept tenant registrations later. Adding or removing a Workflow Engine tenant becomes a control-plane operation during the lifetime of the ASP.NET application.&lt;/p&gt;

&lt;p&gt;The important architectural property is consistency during change. New requests use the updated tenant map, while requests already in progress continue with the view under which they started. Removing a tenant stops new requests from being routed to it without invalidating work that is already using the previous routing state.&lt;/p&gt;

&lt;p&gt;Customer onboarding still spans the wider SaaS control plane:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;provision a database or choose a shared one;&lt;/li&gt;
&lt;li&gt;create and store credentials;&lt;/li&gt;
&lt;li&gt;configure identity, billing, quotas, and product-specific data; and&lt;/li&gt;
&lt;li&gt;register the resulting runtime and tenant mapping with Workflow Engine.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Offboarding has the same separation of concerns. Removing a tenant affects routing, while database lifecycle and retention remain separate. Traffic removal, runtime shutdown, archival, and data erasure should remain explicit operations.&lt;/p&gt;

&lt;p&gt;Adding a physical tenant changes the runtime and provider topology. Adding a logical ID extends an existing shared tenant group. The control plane should model them as distinct operations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Question 3: where is the security boundary?
&lt;/h2&gt;

&lt;p&gt;Tenant routing and tenant authorization are separate decisions. The tenant identifier on a request selects context. Caller identity and permissions establish access to that context.&lt;/p&gt;

&lt;p&gt;An effective boundary has four layers:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Responsibility&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Identity and authorization&lt;/td&gt;
&lt;td&gt;Establish who the caller is and which tenant and operations the caller may access.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tenant routing&lt;/td&gt;
&lt;td&gt;Map the selected logical tenant to the correct runtime and provider.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Workflow persistence&lt;/td&gt;
&lt;td&gt;Keep built-in process reads and writes inside the selected tenant or dedicated database.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Application integration&lt;/td&gt;
&lt;td&gt;Apply the same tenant rule to custom endpoints, actions, external services, and application-owned tables.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Version 22.0.0 strengthens the built-in Workflow Engine Web API path: Data API and RPC API process operations apply the current tenant context to process access.&lt;/p&gt;

&lt;p&gt;Application-wide tenant safety also depends on direct provider access, custom queries, domain tables, file storage, caches, and message handlers carrying the same tenant context. Workflow Engine enforces the data it owns; the application extends that boundary across the rest of the system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Question 4: what is isolated and what may be shared?
&lt;/h2&gt;

&lt;p&gt;The answer differs for operational data and reusable configuration.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Data group&lt;/th&gt;
&lt;th&gt;Tenant behavior&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Process instances and operational records&lt;/td&gt;
&lt;td&gt;Tenant-scoped. This includes process status, parameters, timers, transition history, inbox entries, and approval history.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Workflow definitions&lt;/td&gt;
&lt;td&gt;A standard definition can be shared, while a tenant-specific definition can replace it for one customer.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Forms&lt;/td&gt;
&lt;td&gt;Shared forms can act as defaults, with tenant-specific forms taking priority where configured.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Global Parameters&lt;/td&gt;
&lt;td&gt;Values can live in shared or tenant scope. If the application wants shared values to act as defaults, that fallback should be an explicit policy.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This gives a SaaS product a useful customization model: most customers can run a standard approval flow, while selected customers use a tenant-specific version without requiring another application deployment.&lt;/p&gt;

&lt;p&gt;The safe general rule is simple: process state belongs to one tenant; reusable definitions and configuration may be shared deliberately. Records without a tenant value follow the sharing and fallback policy of their resource type.&lt;/p&gt;

&lt;h2&gt;
  
  
  Question 5: where does Workflow Engine's responsibility end?
&lt;/h2&gt;

&lt;p&gt;Workflow Engine NEO 22.0.0 supplies the workflow-side building blocks: tenant topology, runtime lifecycle, tenant-aware API behavior, and shared or scoped workflow resources. The surrounding SaaS architecture decides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;which customers require dedicated storage;&lt;/li&gt;
&lt;li&gt;how databases, secrets, identities, and non-workflow data are provisioned;&lt;/li&gt;
&lt;li&gt;how users acquire membership in a tenant;&lt;/li&gt;
&lt;li&gt;how long offboarded tenant data is retained;&lt;/li&gt;
&lt;li&gt;how custom application code enforces tenant context; or&lt;/li&gt;
&lt;li&gt;how tenant limits, billing, and product entitlements are applied.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are SaaS architecture and product-policy decisions. Workflow Engine participates in one part of the boundary, and the application completes it. Each responsibility should have an explicit owner.&lt;/p&gt;

&lt;h2&gt;
  
  
  An architecture review checklist
&lt;/h2&gt;

&lt;p&gt;Use this checklist during the architecture review. For every item, record the decision, its owner, and the evidence that confirms it. The review is complete when the team has produced all five artifacts.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] &lt;strong&gt;A tenant placement map.&lt;/strong&gt; Assign each customer segment to a logical, physical, or hybrid topology. Show which tenant IDs share a runtime and database, which customers receive dedicated resources, and which requirement drives each choice.&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;A tenant lifecycle flow.&lt;/strong&gt; Document the complete onboarding and offboarding sequence: infrastructure provisioning, secret creation, tenant registration, traffic activation, routing removal, archival, and deletion. Name the system or team responsible for every step.&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;An authorization rule and its test.&lt;/strong&gt; Define where the tenant ID comes from, how caller membership is verified, and which permissions are required before routing. Add a test that changes the tenant ID while keeping the same identity and confirms that access is rejected.&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;A data ownership matrix.&lt;/strong&gt; Classify processes, operational records, workflow definitions, forms, and Global Parameters as tenant-owned or shared. Record the override and fallback policy for every shared resource type.&lt;/li&gt;
&lt;li&gt;[ ] &lt;strong&gt;A responsibility map for integrations.&lt;/strong&gt; List custom endpoints, direct provider calls, background jobs, application tables, files, caches, and messages. Assign an owner and document how each path receives and enforces tenant context.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The resulting placement map, lifecycle flow, authorization test, data matrix, and responsibility map become the implementation contract for multitenancy. They give developers, security reviewers, and operations teams the same definition of the tenant boundary.&lt;/p&gt;

&lt;p&gt;The detailed migration steps and API changes are in the &lt;a href="https://workflowengine.io/documentation/release-notes/22.0.0/" rel="noopener noreferrer"&gt;Workflow Engine 22.0.0 release notes&lt;/a&gt;. For Workflow Engine NEO licensing options, see &lt;a href="https://optimajet.com/products/pricing/" rel="noopener noreferrer"&gt;Optimajet product pricing&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you want to check our answers against your own architecture, the upgrade details are on &lt;a href="https://workflowengine.io/blog/" rel="noopener noreferrer"&gt;our blog&lt;/a&gt;, and my team does &lt;a href="https://workflowengine.io/contacts/" rel="noopener noreferrer"&gt;demo walkthroughs&lt;/a&gt; where we build the argument on your tenancy model, not ours.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>saas</category>
      <category>architecture</category>
      <category>workflow</category>
    </item>
    <item>
      <title>Workflow Engine NEO trials are self-serve now, and your coding agent can grab one too</title>
      <dc:creator>Optimajet Limited</dc:creator>
      <pubDate>Thu, 11 Jun 2026 14:17:10 +0000</pubDate>
      <link>https://dev.to/optimajet/workflow-engine-neo-trials-are-self-serve-now-and-your-coding-agent-can-grab-one-too-38am</link>
      <guid>https://dev.to/optimajet/workflow-engine-neo-trials-are-self-serve-now-and-your-coding-agent-can-grab-one-too-38am</guid>
      <description>&lt;p&gt;You can grab a Workflow Engine NEO trial key yourself now, no email thread. Go to &lt;strong&gt;&lt;a href="https://trial.workflowengine.io/" rel="noopener noreferrer"&gt;trial.workflowengine.io&lt;/a&gt;&lt;/strong&gt;, type a business email and a company name, and a 30-day Ultimate key shows up in your inbox.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part I'm actually excited about
&lt;/h2&gt;

&lt;p&gt;There's a sibling endpoint for AI coding agents. &lt;code&gt;POST&lt;/code&gt; to &lt;code&gt;https://trial.workflowengine.io/api/trial/llm&lt;/code&gt; with &lt;code&gt;{ "email": "...", "companyName": "..." }&lt;/code&gt; and you get the same key back. Contract is at &lt;a href="https://trial.workflowengine.io/llms.txt" rel="noopener noreferrer"&gt;trial.workflowengine.io/llms.txt&lt;/a&gt;. Business email only (no gmail, yahoo, disposable).&lt;/p&gt;

&lt;p&gt;Two more &lt;code&gt;llms.txt&lt;/code&gt; files live on the docs side and pair with this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://workflowengine.io/llms.txt" rel="noopener noreferrer"&gt;&lt;code&gt;https://workflowengine.io/llms.txt&lt;/code&gt;&lt;/a&gt; is the index of authoritative docs.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://workflowengine.io/documentation/llms-full.txt" rel="noopener noreferrer"&gt;&lt;code&gt;https://workflowengine.io/documentation/llms-full.txt&lt;/code&gt;&lt;/a&gt; is the full reference in one file.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hand all three URLs to your agent (Claude Code, Cursor, Copilot, whatever you use) and it can pull a license and read current docs in the same session. Our library has been through several versions where API names moved around. If your agent writes Workflow Engine NEO code from memory, half the time it'll write something that compiled in 2025.&lt;/p&gt;

&lt;h2&gt;
  
  
  The prompt I give my own agent
&lt;/h2&gt;

&lt;p&gt;Paste this into your agent's system prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You are working with OptimaJet Workflow Engine NEO.

Before writing or recommending code:
1. Fetch https://workflowengine.io/llms.txt for the index of authoritative docs.
2. Fetch https://workflowengine.io/documentation/llms-full.txt for the full reference.
3. Treat these as the source of truth. Do NOT rely on pre-trained knowledge
   of Workflow Engine NEO; the API surface has changed across versions.

If you need a working license to run examples:
- POST {"email":"you@yourcompany.com","companyName":"Your Co"} to
  https://trial.workflowengine.io/api/trial/llm
- The contract is documented at https://trial.workflowengine.io/llms.txt
- Business email required (no gmail/yahoo/disposable). Three keys max per email.
- The key is returned in the response body and also emailed.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When those three URLs are included in the context, your agent’s code actually compiles. Without them, it picks the wrong overload most of the time.&lt;/p&gt;

&lt;p&gt;If you grab a key and run into something the docs don't cover, or you want help planning a rollout, book a call at &lt;strong&gt;&lt;a href="https://workflowengine.io/contacts/" rel="noopener noreferrer"&gt;workflowengine.io/contacts/&lt;/a&gt;&lt;/strong&gt;. Bring a concrete task and we can scope a free POC.&lt;/p&gt;

&lt;p&gt;Tell us in the comments if anything here reads off.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>ai</category>
      <category>agents</category>
      <category>workflow</category>
    </item>
    <item>
      <title>When to use Data API vs RPC API in Workflow Engine NEO: a .NET architect's guide</title>
      <dc:creator>Optimajet Limited</dc:creator>
      <pubDate>Tue, 19 May 2026 16:22:40 +0000</pubDate>
      <link>https://dev.to/optimajet/when-to-use-data-api-vs-rpc-api-in-workflow-engine-neo-a-net-architects-guide-3cd5</link>
      <guid>https://dev.to/optimajet/when-to-use-data-api-vs-rpc-api-in-workflow-engine-neo-a-net-architects-guide-3cd5</guid>
      <description>&lt;p&gt;I am Mike Lukinov, co-founder of &lt;a href="https://optimajet.com/" rel="noopener noreferrer"&gt;Optimajet&lt;/a&gt;. Since 2022, I have been closely involved in customer architecture and developer experience work around &lt;a href="https://optimajet.com/workflowengine/" rel="noopener noreferrer"&gt;Workflow Engine by Optimajet&lt;/a&gt;. I sit in most customer architecture meetings where Workflow Engine NEO questions repeat. The pattern I see most often when teams adopt Workflow Engine NEO is this: an architect picks the RPC API for every integration because "the RPC API is the obvious API." Six months later that team has a BI dashboard, a mobile app, and a partner integration all calling the same RPC surface, and a security review is asking why a read-only analyst token can start and cancel processes. This is the article I wrote instead of answering each case from scratch.&lt;/p&gt;

&lt;p&gt;Workflow Engine NEO ships two HTTP surfaces, the Data API and the RPC API; the choice between them is a security and blast-radius decision, not a syntax preference. Everything below is personal opinion, grounded in those customer conversations. Throughout I mark each block as &lt;strong&gt;Documented behavior&lt;/strong&gt;, &lt;strong&gt;Architectural recommendation&lt;/strong&gt;, or &lt;strong&gt;Risk if ignored&lt;/strong&gt;, so you can separate Optimajet facts from opinion. The framing should hold even if you pick a different boundary.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Version note.&lt;/strong&gt; The code examples below target Workflow Engine NEO v21.0.0 and later, where Web API authorization uses a compact &lt;code&gt;WorkflowApiPermissions&lt;/code&gt; claim and the builder API. If you are on v20.x or earlier, check the matching documentation for the older per-operation claim format; do not copy v21 snippets into a v20 project.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the Workflow Engine NEO Data API and RPC API actually do
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Documented behavior.&lt;/strong&gt; According to the &lt;a href="https://workflowengine.io/documentation/web-api" rel="noopener noreferrer"&gt;Workflow Engine Web API setup documentation retrieved 2026-05-12&lt;/a&gt;, each surface has a one-sentence definition:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"RPC API: Remotely manage Workflow Engine Runtime instances in single-tenant or multi-tenant modes."&lt;br&gt;
"RESTful Data API: Interact safely with the Workflow Engine database without disrupting internal processes."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The Web API Core is provided by &lt;a href="https://www.nuget.org/packages/OptimaJet.Workflow.Api" rel="noopener noreferrer"&gt;&lt;code&gt;OptimaJet.Workflow.Api&lt;/code&gt;&lt;/a&gt; for .NET 8.0, and Data access is added through a provider-specific package such as &lt;code&gt;OptimaJet.Workflow.Api.Mssql&lt;/code&gt;, &lt;code&gt;OptimaJet.Workflow.Api.Postgres&lt;/code&gt;, &lt;code&gt;OptimaJet.Workflow.Api.Mysql&lt;/code&gt;, &lt;code&gt;OptimaJet.Workflow.Api.Oracle&lt;/code&gt;, &lt;code&gt;OptimaJet.Workflow.Api.Sqlite&lt;/code&gt;, or &lt;code&gt;OptimaJet.Workflow.Api.Mongo&lt;/code&gt;. Workflow Engine NEO is a licensed feature set on top of base Workflow Engine starting from v19.0.0; the RPC API and Web API multitenancy were introduced in v19.0.0 per the &lt;a href="https://workflowengine.io/documentation/release-notes/19.0.0" rel="noopener noreferrer"&gt;19.0.0 release notes&lt;/a&gt;. The two surfaces share the same multi-tenant header, &lt;code&gt;Workflow-Api-Tenant-ID&lt;/code&gt;, the same &lt;code&gt;WorkflowApiPermissions&lt;/code&gt; claim model, and are exposed through the same Workflow Engine Web API service with a generated OpenAPI specification. What differs is the operations branch each one exposes, and that difference is where the design intent lives.&lt;/p&gt;

&lt;p&gt;The Web API requires a Workflow Engine license key with the API/NEO option enabled; without the key, the API does not start. The Data/RPC split is therefore a paid Workflow Engine NEO capability; base Workflow Engine and the free Workflow Engine Community Edition do not include either API, per the &lt;a href="https://optimajet.com/products/workflowengine/price/" rel="noopener noreferrer"&gt;Workflow Engine pricing and editions page&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to use the Workflow Engine NEO Data API
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Architectural recommendation.&lt;/strong&gt; Use the Data API as the default integration boundary for reporting, audit export, BI dashboards, and support tools that should observe workflow state without driving runtime behavior. The Data API is the right place to surface workflow data to consumers whose blast radius you want to keep small.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Documented behavior, important clarification.&lt;/strong&gt; The Data API is not strictly read-only. The documented Data API surface includes create, update, and delete operations for several entities, among them global parameters, workflow schemes, process parameters, timers, transitions, approvals, and inbox entries. Calling the Data API does not move a process through state transitions the way an RPC command does, but the Data API can mutate the underlying data. Read-only consumers must therefore receive only the specific &lt;code&gt;get&lt;/code&gt; and &lt;code&gt;get-collection&lt;/code&gt; permissions for the entities they need, not a blanket allow over the Data API surface.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Architectural recommendation, with v21 code.&lt;/strong&gt; A practical scope for a read-only analyst persona uses the v21 &lt;code&gt;WorkflowApiPermissions&lt;/code&gt; builder API to deny everything by default, scope to a single tenant, and then explicitly allow concrete read operations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;claim&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;permissions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;BuildClaim&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;DenyAllOperations&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;DenyAllTenantsExcept&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"TenantA"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Allow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="s"&gt;"workflow-api.data.schemes.get"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"workflow-api.data.schemes.get-collection"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"workflow-api.data.processes.get"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"workflow-api.data.processes.get-collection"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"workflow-api.data.processes.parameters.get"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"workflow-api.data.processes.parameters.get-collection"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"workflow-api.data.processes.transitions.get"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"workflow-api.data.processes.transitions.get-collection"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"workflow-api.data.processes.approvals.get"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"workflow-api.data.processes.approvals.get-collection"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"workflow-api.data.processes.inbox-entries.get"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"workflow-api.data.processes.inbox-entries.get-collection"&lt;/span&gt;
    &lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This token reads schemes, process records, parameters, transitions, approvals, and inbox entries inside &lt;code&gt;TenantA&lt;/code&gt;; it cannot mutate any Data entity or reach other tenants. For cross-tenant analyst access, replace &lt;code&gt;DenyAllTenantsExcept("TenantA")&lt;/code&gt; with &lt;code&gt;AllowAllTenants()&lt;/code&gt; as an explicit administrative decision.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note on process history.&lt;/strong&gt; Process-history operations (&lt;code&gt;get-process-history&lt;/code&gt;, &lt;code&gt;get-process-history-count&lt;/code&gt;) live under &lt;code&gt;workflow-api.rpc.*&lt;/code&gt;, not the Data API. A reporting client that needs them should receive them as scoped read-only RPC exceptions.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to use the Workflow Engine NEO RPC API
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Architectural recommendation.&lt;/strong&gt; Use the RPC API when the caller is meant to drive the runtime: start instances, execute commands, advance state. Bulk operations live exclusively on the RPC API, so any client that needs to start or progress many processes in one round-trip belongs here.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Documented behavior.&lt;/strong&gt; The operations branch &lt;code&gt;workflow-api.rpc&lt;/code&gt; covers, among others, &lt;code&gt;workflow-api.rpc.bulk-create-instance&lt;/code&gt;, &lt;code&gt;workflow-api.rpc.bulk-execute-command&lt;/code&gt;, &lt;code&gt;workflow-api.rpc.bulk-get-process-instance&lt;/code&gt;, &lt;code&gt;workflow-api.rpc.get-available-commands&lt;/code&gt;, &lt;code&gt;workflow-api.rpc.delete-instance&lt;/code&gt;, and &lt;code&gt;workflow-api.rpc.get-process-history&lt;/code&gt;, per the &lt;a href="https://workflowengine.io/documentation/web-api" rel="noopener noreferrer"&gt;Workflow Engine documentation&lt;/a&gt;. Bulk operations, including both read-like bulk retrieval and runtime-changing operations, live under the RPC API branch.&lt;/p&gt;

&lt;p&gt;The RPC API is the right surface for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Polyglot integration. A Node.js worker, a Python ETL job, or a Java partner service that needs to start and progress Workflow Engine processes does so over plain HTTP using the RPC API. The host application stays on .NET, but the callers do not have to.&lt;/li&gt;
&lt;li&gt;Front-end clients that drive workflows directly, such as a React or Angular UI that maps user actions onto &lt;code&gt;workflow-api.rpc.execute-command&lt;/code&gt; or &lt;code&gt;workflow-api.rpc.bulk-execute-command&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Backend microservices that orchestrate Workflow Engine state from outside the host process.
&lt;strong&gt;Risk if ignored.&lt;/strong&gt; Each RPC operation has a separate permission identifier. A token authorised for &lt;code&gt;workflow-api.rpc.execute-command&lt;/code&gt; does not automatically gain access to &lt;code&gt;workflow-api.rpc.delete-instance&lt;/code&gt;. In practice, however, teams tend to grant broad RPC allow lists to operational clients, which is where the real blast radius shows up. Keep &lt;code&gt;execute-command&lt;/code&gt;, &lt;code&gt;delete-instance&lt;/code&gt;, runtime control, and bulk operations in separate permission profiles, and only combine them inside dedicated admin tokens that you audit.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How &lt;code&gt;WorkflowApiPermissions&lt;/code&gt; enforces the Data/RPC split at the claim level
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Documented behavior.&lt;/strong&gt; The Workflow Engine NEO permission model treats the Data/RPC split as a security primitive. Each operation has a concrete identifier under either &lt;code&gt;workflow-api.data.*&lt;/code&gt; or &lt;code&gt;workflow-api.rpc.*&lt;/code&gt;, and tokens are issued by passing concrete identifiers to the &lt;code&gt;WorkflowApiPermissions&lt;/code&gt; builder. The Workflow Engine documentation states verbatim: "Operations are hierarchical. More specific rule wins on conflict."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Architectural recommendation.&lt;/strong&gt; Build claims from concrete operation identifiers. The pattern works for both Data API and RPC API personas:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Persona&lt;/th&gt;
&lt;th&gt;Builder pattern&lt;/th&gt;
&lt;th&gt;What the token can do&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;BI analyst, Data API only&lt;/td&gt;
&lt;td&gt;Deny all operations, allow concrete Data API operations ending with &lt;code&gt;.get&lt;/code&gt; or &lt;code&gt;.get-collection&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Read schemes, process records, parameters, transitions, approvals, and inbox entries; cannot create, update, or delete&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Workflow operator, RPC without destructive ops&lt;/td&gt;
&lt;td&gt;Deny all operations, allow concrete RPC operations except &lt;code&gt;delete-instance&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Start instances, execute commands, read; cannot delete&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Admin excluding one tenant&lt;/td&gt;
&lt;td&gt;Allow all operations, then &lt;code&gt;AllowAllTenantsExcept("TenantX")&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Full admin access except the excluded tenant&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tenant-scoped admin&lt;/td&gt;
&lt;td&gt;Allow all operations, then &lt;code&gt;DenyAllTenantsExcept("TenantA")&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Full admin access inside one tenant only&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Recipe table compiled from the v21 &lt;code&gt;WorkflowApiPermissions&lt;/code&gt; builder examples in the Workflow Engine documentation, retrieved 2026-05-12.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Risk if ignored.&lt;/strong&gt; The same compact format describes tenant access. A note on multi-tenancy from the Workflow Engine documentation: "The tenant header selects the tenant context only. It is not an authorization source. When security services are enabled, the current &lt;code&gt;WorkflowApiPermissions&lt;/code&gt; claim must also allow the selected tenant. If the tenant permission is missing... the request is rejected with 403 Forbidden." Architects who treat the &lt;code&gt;Workflow-Api-Tenant-ID&lt;/code&gt; header as an authorization signal will eventually ship a tenant-cross-bleed bug. The header is routing; the claim is authorization.&lt;/p&gt;

&lt;p&gt;A note for v21.0.0 readers: &lt;code&gt;IWorkflowApiPermissions&lt;/code&gt; was redesigned in v21.0.0 and the synchronous API was removed across both the Data API and the RPC API, per the &lt;a href="https://workflowengine.io/documentation/release-notes/workflow-engine/" rel="noopener noreferrer"&gt;Workflow Engine release notes retrieved 2026-05-12&lt;/a&gt;. Earlier per-operation claim helpers such as &lt;code&gt;AllowAll&lt;/code&gt;, &lt;code&gt;AllowList&lt;/code&gt;, &lt;code&gt;DenyAll&lt;/code&gt;, &lt;code&gt;DenyList&lt;/code&gt;, &lt;code&gt;GetAllPermissions&lt;/code&gt;, and &lt;code&gt;ValidatePermissions&lt;/code&gt; were removed; use the compact &lt;code&gt;WorkflowApiPermissions&lt;/code&gt; claim and the &lt;code&gt;BuildClaim&lt;/code&gt; builder API from v21.0.0 onward.&lt;/p&gt;

&lt;p&gt;Note: some public security pages still show pre-v21 helpers like &lt;code&gt;AllowList(...)&lt;/code&gt;. Follow the v21 release notes; treat older snippets as v20.x reference.&lt;/p&gt;

&lt;h2&gt;
  
  
  A decision table: which Workflow Engine NEO API does my caller need?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Architectural recommendation.&lt;/strong&gt; The table below is the one I draw on whiteboards in support calls.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Use case&lt;/th&gt;
&lt;th&gt;Prefer&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;th&gt;Permission style&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;BI dashboard&lt;/td&gt;
&lt;td&gt;Data API&lt;/td&gt;
&lt;td&gt;Reads process records, parameters, transitions, approvals, and related Data API entities without runtime commands&lt;/td&gt;
&lt;td&gt;Only concrete &lt;code&gt;get&lt;/code&gt; and &lt;code&gt;get-collection&lt;/code&gt; permissions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Read-only support panel&lt;/td&gt;
&lt;td&gt;Data API&lt;/td&gt;
&lt;td&gt;Lower operational blast radius&lt;/td&gt;
&lt;td&gt;No create, update, or delete permissions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Audit and evidence export&lt;/td&gt;
&lt;td&gt;Data API&lt;/td&gt;
&lt;td&gt;Snapshot of state without affecting running work&lt;/td&gt;
&lt;td&gt;Read-only Data API allow list&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;External service starts workflows&lt;/td&gt;
&lt;td&gt;RPC API&lt;/td&gt;
&lt;td&gt;Requires runtime command execution&lt;/td&gt;
&lt;td&gt;Only &lt;code&gt;create-instance&lt;/code&gt;, &lt;code&gt;execute-command&lt;/code&gt;, possibly &lt;code&gt;get-available-commands&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Front-end UI executes commands&lt;/td&gt;
&lt;td&gt;RPC API&lt;/td&gt;
&lt;td&gt;Maps user actions onto runtime transitions&lt;/td&gt;
&lt;td&gt;Per-user token scoped by tenant and command set&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Admin runtime control&lt;/td&gt;
&lt;td&gt;RPC API&lt;/td&gt;
&lt;td&gt;Requires start, stop, delete, status operations&lt;/td&gt;
&lt;td&gt;Separate privileged token, audited&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsmm7azdl0nlka5fqq91o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsmm7azdl0nlka5fqq91o.png" alt="Data API vs RPC API decision canvas" width="799" height="620"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Decision canvas compiled by the author from the Workflow Engine NEO operation branches, 2026-05-12.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Risk if ignored.&lt;/strong&gt; In multi-tenant deployments, avoid relying on an implicit default tenant for external clients. Prefer requiring every caller to send &lt;code&gt;Workflow-Api-Tenant-ID&lt;/code&gt;, and ensure the token's &lt;code&gt;WorkflowApiPermissions&lt;/code&gt; claim also allows that tenant. Default-deny on the operation tree, allow only the concrete operations the caller's job needs, deny destructive operations explicitly, per the &lt;a href="https://workflowengine.io/documentation/web-api/core" rel="noopener noreferrer"&gt;Workflow API core services documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Take this to your team
&lt;/h2&gt;

&lt;p&gt;If you are the architect deciding how to surface Workflow Engine NEO to the rest of your organisation, here is the short version to bring to a design review.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Decision rule.&lt;/strong&gt; Pick the Data API for any caller whose job description does not include changing runtime state. Pick the RPC API when the caller must drive the runtime, accepting that the token will carry a larger blast radius. Scope every token, on both APIs, from concrete operation identifiers via the v21 builder API; do not rely on conceptual branch names, and do not rely on the absence of UI affordances. The Data API is safer as an integration boundary, but only with a narrow allow list of read permissions. The API itself is not automatically read-only.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Candidate filter.&lt;/strong&gt; With one trusted caller and no audit, BI, or analyst workload on the horizon, you can put everything behind the RPC API for now. With more than one consumer of workflow state, such as an analyst tool, a mobile app, or a partner service, split early. Retrofitting permission boundaries after the first quarter in production is expensive.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cost of getting it wrong.&lt;/strong&gt; A single RPC token with a broad allow list that lands in a BI tool can move workflow state in ways the audit log records but nobody watches. The same is true of a Data API token granted at branch level when the consumer needs only reads. I have seen both patterns in customer support conversations. The fix is organisational, not code: revoke the token, audit downstream callers, and explain to compliance why a read tool had write access for an unknown window.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Anticipated pushbacks.&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;"REST is simpler than two surfaces."&lt;/em&gt; Both APIs are REST/HTTP and share an OpenAPI document; one generator produces one client. The operation tree is what you scope against, so the choice adds a permission boundary, not a protocol.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;"We can just gate on roles in the host app."&lt;/em&gt; Role checks in the host app hold only until somebody calls Workflow Engine NEO directly with a valid token. &lt;code&gt;WorkflowApiPermissions&lt;/code&gt; enforces the boundary at the runtime, regardless of caller.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;"We do not have multi-tenancy, so the security model is overkill."&lt;/em&gt; The Data/RPC split is independent of multi-tenancy. A single-tenant deployment still benefits from a read-only Data API token for analytics and a separate privileged profile for destructive RPC operations.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A personal note from the author
&lt;/h2&gt;

&lt;p&gt;Thank you for reading. If you have shipped Workflow Engine NEO and you split your Data and RPC clients differently from how I described, or chose not to split at all, I would like to hear about it. The support conversations I draw from are biased toward teams who are already debating the trade-off, and there are deployment patterns I will not see from where I sit.&lt;/p&gt;

&lt;p&gt;The Data API and the RPC API are part of the licensed Workflow Engine NEO tier and I have a commercial interest in your choice. Treat the framing above as a starting point, not the end. If you disagree with the decision rule, please leave a comment below or push back on &lt;a href="https://www.linkedin.com/in/mikelukinov/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;; that feedback will make the next article in this series sharper.&lt;/p&gt;

&lt;p&gt;If you would rather walk through your own architecture, &lt;a href="https://workflowengine.io/contacts/" rel="noopener noreferrer"&gt;book a demo at workflowengine.io&lt;/a&gt;. Come with a concrete task and constraints, and we will help you scope a free POC against Workflow Engine NEO so you can validate the Data/RPC split on your real data before committing.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>architecture</category>
      <category>api</category>
      <category>saas</category>
    </item>
    <item>
      <title>React JSON Schema Form Alternative: FormEngine vs RJSF Bundle Size Comparison</title>
      <dc:creator>Optimajet Limited</dc:creator>
      <pubDate>Wed, 11 Feb 2026 19:19:23 +0000</pubDate>
      <link>https://dev.to/optimajet/formengine-vs-rjsf-an-honest-bundle-size-comparison-of-two-json-schema-form-libraries-133n</link>
      <guid>https://dev.to/optimajet/formengine-vs-rjsf-an-honest-bundle-size-comparison-of-two-json-schema-form-libraries-133n</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; Hi! We're the team at &lt;a href="https://optimajet.com" rel="noopener noreferrer"&gt;Optimajet&lt;/a&gt;, creators of FormEngine. This is an honest technical comparison of our library with react-jsonschema-form (RJSF). All tests are public, reproducible, and &lt;a href="https://github.com/optimajet/formengine/tree/master/community/examples/bundle-size" rel="noopener noreferrer"&gt;available on GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; We compared two direct competitors in the JSON-based React forms space. RJSF is lighter out of the box (175 KB vs 244 KB). But if you already have Material UI &lt;strong&gt;FormEngine becomes 23% lighter&lt;/strong&gt; (188 KB), while RJSF gets 32% heavier (232 KB). &lt;strong&gt;Your choice of UI library determines the winner.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Why RJSF vs FormEngine? 🤔
&lt;/h2&gt;

&lt;p&gt;When we developed FormEngine, we often heard: "How are you different from react-jsonschema-form?"&lt;/p&gt;

&lt;p&gt;Fair question. Both libraries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;React-based&lt;/li&gt;
&lt;li&gt;Work with JSON:

&lt;ul&gt;
&lt;li&gt;RJSF uses JSON Schema to describe forms&lt;/li&gt;
&lt;li&gt;FormEngine uses its own JSON format&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Support Material UI&lt;/li&gt;

&lt;li&gt;Open to customization&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;But there's one fundamental architectural difference that &lt;strong&gt;radically affects bundle size&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;RJSF&lt;/strong&gt; — adds UI components on top of the base library&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FormEngine&lt;/strong&gt; — completely replaces UI components during integration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's see how this works in practice.&lt;/p&gt;




&lt;h2&gt;
  
  
  Testing Methodology
&lt;/h2&gt;

&lt;p&gt;We tested two realistic forms:&lt;/p&gt;

&lt;h3&gt;
  
  
  Login Form (Simple Case)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Email + Password fields&lt;/li&gt;
&lt;li&gt;Basic validation&lt;/li&gt;
&lt;li&gt;Submit button&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Booking Form (Complex Case)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Multi-step form&lt;/li&gt;
&lt;li&gt;Conditional logic&lt;/li&gt;
&lt;li&gt;Different field types (text, dates, selects)&lt;/li&gt;
&lt;li&gt;Validation at each step&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Test Conditions:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Production build (minified + gzipped)&lt;/li&gt;
&lt;li&gt;Vite as bundler&lt;/li&gt;
&lt;li&gt;Tree-shaking enabled&lt;/li&gt;
&lt;li&gt;Default configurations&lt;/li&gt;
&lt;li&gt;Two variants: with default UI (FormEngine Core has no default UI, React Suite v5 was used) and with Material UI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Full methodology: &lt;a href="https://formengine.io/documentation/bundle-size-comparison" rel="noopener noreferrer"&gt;formengine.io/documentation/bundle-size-comparison&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Results (gzip sizes)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Login Form - Default UI
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;🥇 RJSF           175.26 KB  (baseline)
🥈 FormEngine + React Suite (v5)   244.19 KB  (+39% heavier)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;RJSF wins&lt;/strong&gt; in its pure form. Bootstrap CSS is lighter than React Suite.&lt;/p&gt;




&lt;h3&gt;
  
  
  Login Form - With Material UI
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;🥇 FormEngine     188.54 KB  (-23% from default!)  
🥈 RJSF           231.62 KB  (+32% from default)

Difference: 43 KB in favor of FormEngine
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The picture changes!&lt;/strong&gt; FormEngine becomes lighter when replacing React Suite with MUI.&lt;/p&gt;




&lt;h3&gt;
  
  
  Booking Form - Default UI
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;🥇 RJSF           178.07 KB  (baseline)
🥈 FormEngine + React Suite (v5)    316.69 KB  (+78% heavier)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;RJSF is ahead again. But the difference has grown — complex forms require more components.&lt;/p&gt;




&lt;h3&gt;
  
  
  Booking Form - With Material UI
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;🥇 FormEngine     199.26 KB  (-37% from default!)  
🥈 RJSF           234.50 KB  (+32% from default)

Difference: 35 KB in favor of FormEngine
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;FormEngine is lighter again&lt;/strong&gt; after MUI integration.&lt;/p&gt;




&lt;h2&gt;
  
  
  Key Insight: How UI Kit Changes Everything
&lt;/h2&gt;

&lt;p&gt;Here's what happens when switching from default UI to Material UI:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Form&lt;/th&gt;
&lt;th&gt;FormEngine&lt;/th&gt;
&lt;th&gt;RJSF&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Login&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;-55.6 KB (-23%)&lt;/strong&gt; ⬇️&lt;/td&gt;
&lt;td&gt;+56.4 KB (+32%) ⬆️&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Booking&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;-117.4 KB (-37%)&lt;/strong&gt; ⬇️&lt;/td&gt;
&lt;td&gt;+56.4 KB (+32%) ⬆️&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Why Does FormEngine Become Lighter?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Comparison of Different UI Library Usage:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FormEngine + React Suite by default:
├── Core engine (~50 KB)
├── React Suite components (~190 KB)
└── React Suite CSS (~52 KB)
= 244 KB total

FormEngine + MUI:
├── Core engine (~50 KB)
├── MUI components (already in project)
└── Minimal CSS (~0.2 KB)
= 188 KB total (-23%)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why Does RJSF Become Heavier?
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Additive Architecture:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;RJSF by default:
├── Core engine (~156 KB)
└── Bootstrap CSS (~19 KB)
= 175 KB total

RJSF + MUI:
├── Core engine (~156 KB)
├── MUI adapter layer (~20 KB)
├── MUI components (already in project)
└── Minimal CSS (~0.2 KB)
= 232 KB total (+32%)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;MUI is &lt;strong&gt;added on top&lt;/strong&gt;, not replacing the base components.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Does This Mean for Real Users?
&lt;/h2&gt;

&lt;p&gt;A difference of 35-43 KB might seem small, but let's translate it into seconds:&lt;/p&gt;

&lt;h3&gt;
  
  
  On Slow 3G (Emerging Markets):
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;43 KB Difference&lt;/th&gt;
&lt;th&gt;Impact&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Load&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~1.2 sec&lt;/td&gt;
&lt;td&gt;Slower UI appearance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;TTI&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~1.0 sec&lt;/td&gt;
&lt;td&gt;Slower interactivity&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  On 4G (Typical Conditions):
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;43 KB Difference&lt;/th&gt;
&lt;th&gt;Impact&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Load&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~0.13 sec&lt;/td&gt;
&lt;td&gt;Almost imperceptible&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;TTI&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~0.15 sec&lt;/td&gt;
&lt;td&gt;Barely noticeable&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Conclusion:&lt;/strong&gt; If you have users on slow networks (emerging markets, mobile internet in subways, poor WiFi) — every second is critical.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusions (And What We Learned About Our Own Product)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. &lt;strong&gt;Context Is Everything&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;You can't say "FormEngine is better than RJSF" or vice versa. The right answer depends on your project:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Choose RJSF if:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Need minimal baseline&lt;/li&gt;
&lt;li&gt;JSON Schema is your primary source of truth&lt;/li&gt;
&lt;li&gt;Simple forms with basic validation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Choose FormEngine if:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Already using Material UI or another UI kit&lt;/li&gt;
&lt;li&gt;Need deep component customization&lt;/li&gt;
&lt;li&gt;Complex forms with conditional logic&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. &lt;strong&gt;Our Competitive Advantage Is Integration&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;We initially designed FormEngine for &lt;strong&gt;embedding into existing projects&lt;/strong&gt; with already installed UI libraries. This architectural decision paid off:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Minus 23-37% bundle when integrating with MUI compared to React Suite&lt;/li&gt;
&lt;li&gt;Complete UI replacement instead of layering&lt;/li&gt;
&lt;li&gt;Zero overhead for components&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. &lt;strong&gt;Different Approach to Describing Forms in JSON&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;This is one of the most important differences that affects not only DX but also bundle size:&lt;/p&gt;

&lt;h4&gt;
  
  
  RJSF: Separate Schemas (Data Schema + UI Schema)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;data-schema.json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;describes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;data&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"format"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"email"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"password"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"minLength"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"required"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"password"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ui-schema.json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;describes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;UI&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ui:widget"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ui:placeholder"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Enter your email"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"password"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ui:widget"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"password"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ui:help"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Min 8 characters"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Pros of Separation:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅&lt;strong&gt;Standardization&lt;/strong&gt; — JSON Schema is an open standard&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Reusability&lt;/strong&gt; — one data schema can be used in different UIs&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Validation independent of UI&lt;/strong&gt; — can validate on backend with the same schema&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Ecosystem&lt;/strong&gt; — many tools for JSON Schema (generators, validators, documentation)&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Separation of concerns&lt;/strong&gt; — logic separate from presentation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons of Separation:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;❌ &lt;strong&gt;Synchronization&lt;/strong&gt; — need to maintain two files in sync&lt;/li&gt;
&lt;li&gt;❌ &lt;strong&gt;Verbosity&lt;/strong&gt; — more code for simple forms&lt;/li&gt;
&lt;li&gt;❌ &lt;strong&gt;Learning curve&lt;/strong&gt; — need to know both formats&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  FormEngine: Unified JSON (Data + UI in One JSON)
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;form.json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;everything&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;one&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;place&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"components"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"TextField"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"key"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Email"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"placeholder"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Enter your email"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"validation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"required"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PasswordField"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"key"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"password"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Password"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"help"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Min 8 characters"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"validation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"required"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"minLength"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Pros of Unification:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ &lt;strong&gt;Simplicity&lt;/strong&gt; — one file, one source of truth&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Less code&lt;/strong&gt; — no duplication of field names&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Conditional logic&lt;/strong&gt; — easier to describe dependencies between fields&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;DX&lt;/strong&gt; — faster to write and understand&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;Compactness&lt;/strong&gt; — less boilerplate&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cons of Unification:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;❌ &lt;strong&gt;No standardization&lt;/strong&gt; — proprietary FormEngine format&lt;/li&gt;
&lt;li&gt;❌ &lt;strong&gt;Vendor lock-in&lt;/strong&gt; — harder to migrate to another library&lt;/li&gt;
&lt;li&gt;❌ &lt;strong&gt;Validation only on client&lt;/strong&gt; — can't reuse schema on backend directly&lt;/li&gt;
&lt;li&gt;❌ &lt;strong&gt;Fewer tools&lt;/strong&gt; — no JSON Schema ecosystem&lt;/li&gt;
&lt;li&gt;❌ &lt;strong&gt;UI and data coupling&lt;/strong&gt; — UI changes can affect logic&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Impact on Bundle Size
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;RJSF (separate schemas):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✅ JSON Schema validator (~15-20 KB)
✅ Standard ajv (might already be in project)
❌ UI Schema parser (~5 KB)
❌ Mapping layer between schemas (~3-5 KB)

Total: ~23-30 KB overhead
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;FormEngine (unified schema):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;✅ Custom validator (~8-12 KB)
✅ Less parsing
❌ No ajv reuse
❌ Proprietary format

Total: ~8-12 KB overhead
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Conclusion:&lt;/strong&gt; FormEngine saves ~10-15 KB on schema parsing, but loses standardization benefits.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important note:&lt;/strong&gt; Although FormEngine uses a proprietary format, it is fully open and &lt;a href="https://formengine.io/documentation/formengine-core/forms-json" rel="noopener noreferrer"&gt;documented&lt;/a&gt;. This means you can study the specification, write your own parsers or form generators, without depending on closed solutions.&lt;/p&gt;




&lt;h3&gt;
  
  
  Real Example: Complex Conditional Logic
&lt;/h3&gt;

&lt;p&gt;Imagine a form where the "Phone" field is shown only if "Contact by phone" is selected:&lt;/p&gt;

&lt;h4&gt;
  
  
  RJSF Approach:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;data-schema.json&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"contactMethod"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"enum"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"phone"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"phone"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"pattern"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^[0-9]{10}$"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"phone"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"contactMethod"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"if"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"contactMethod"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"const"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"phone"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"then"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"required"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"phone"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ui-schema.json&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"phone"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ui:widget"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"phone"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ui:options"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"conditional"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"show"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"field"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"contactMethod"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"is"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"phone"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; The condition is described in two places! Data schema says "phone required if...", UI schema says "show phone if...". Need to synchronize.&lt;/p&gt;

&lt;h4&gt;
  
  
  FormEngine Approach:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"components"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"RadioGroup"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"key"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"contactMethod"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Contact method"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"options"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Email"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"phone"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Phone"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"PhoneField"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"key"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"phone"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Phone number"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"conditional"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"show"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{{contactMethod === 'phone'}}"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"validation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"required"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{{contactMethod === 'phone'}}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"pattern"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^[0-9]{10}$"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Advantage:&lt;/strong&gt; Condition described once. UI and validation automatically synchronized.&lt;/p&gt;




&lt;h3&gt;
  
  
  When Is Each Approach Better?
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Choose RJSF (separate schemas) if:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;You already have JSON Schema for API validation&lt;/li&gt;
&lt;li&gt;Need one schema for frontend and backend&lt;/li&gt;
&lt;li&gt;Working in a team where backend generates schemas&lt;/li&gt;
&lt;li&gt;Using JSON Schema ecosystem tools&lt;/li&gt;
&lt;li&gt;Need compatibility with third-party systems&lt;/li&gt;
&lt;li&gt;Simple forms without complex conditional logic&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Choose FormEngine (unified schema) if:
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Forms are complex with many conditions&lt;/li&gt;
&lt;li&gt;UI logic is more important than data validation&lt;/li&gt;
&lt;li&gt;Want to avoid duplication&lt;/li&gt;
&lt;li&gt;DX and development speed are priorities&lt;/li&gt;
&lt;li&gt;Not planning to migrate to another library&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  4. &lt;strong&gt;Transparency Builds Trust&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;We've published all data, including scenarios where RJSF is faster. This is our principle: &lt;strong&gt;honesty is more important than marketing&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If you find errors in the tests — &lt;a href="https://github.com/optimajet/formengine/issues" rel="noopener noreferrer"&gt;open an issue&lt;/a&gt;, we'll fix it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Detailed Data
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Comparison Table (All Scenarios)
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;RJSF (gzip)&lt;/th&gt;
&lt;th&gt;FormEngine (gzip)&lt;/th&gt;
&lt;th&gt;Winner&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Login default UI&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;175.26 KB&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;244.19 KB&lt;/td&gt;
&lt;td&gt;RJSF (-39%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Login MUI&lt;/td&gt;
&lt;td&gt;231.62 KB&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;188.54 KB&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;FormEngine (-19%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Booking default UI&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;178.07 KB&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;316.69 KB&lt;/td&gt;
&lt;td&gt;RJSF (-78%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Booking MUI&lt;/td&gt;
&lt;td&gt;234.50 KB&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;199.26 KB&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;FormEngine (-15%)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Detailed Bundle Breakdown
&lt;/h3&gt;

&lt;h4&gt;
  
  
  RJSF Login (default UI):
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Code:     480.72 KB raw / 156.37 KB gzip (80%)
CSS:      117.18 KB raw / 19.27 KB gzip (20%)
Total:    597.91 KB raw / 175.64 KB gzip
Chunks:   2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  FormEngine Login (default UI):
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Code:     626.23 KB raw / 192.65 KB gzip (59%)
CSS:      438.18 KB raw / 52.42 KB gzip (41%)
Total:    1.04 MB raw / 245.07 KB gzip
Chunks:   2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  RJSF Login (MUI):
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Code:     725.19 KB raw / 232.47 KB gzip (100%)
CSS:      186 B raw / 169 B gzip (0%)
Total:    725.37 KB raw / 232.64 KB gzip
Chunks:   2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  FormEngine Login (MUI):
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Code:     622.22 KB raw / 189.27 KB gzip (100%)
CSS:      186 B raw / 169 B gzip (0%)
Total:    622.40 KB raw / 189.44 KB gzip
Chunks:   2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Observation:&lt;/strong&gt; After switching to MUI, CSS practically disappears for both libraries (186 bytes). The entire difference is in the JS code.&lt;/p&gt;




&lt;h2&gt;
  
  
  Practical Recommendations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  If You DON'T Have a UI Library in Your Project:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Recommendation: RJSF

Reason: 
- Lighter out of the box (175 KB vs 244 KB)
- Faster setup
- No need to choose UI kit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  If You HAVE Material UI:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Recommendation: FormEngine

Reason:
- Lighter with MUI (188 KB vs 232 KB)
- No duplication of UI code
- Full integration with your Design System
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  If You Have Another UI Kit (Ant Design, Chakra, etc):
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Recommendation: Depends on adapter availability

RJSF: Has adapters for many UI kits
FormEngine: Currently only MUI and React Suite

Check documentation for both libraries
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  If Planning to Change UI Kit in the Future:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Recommendation: FormEngine

Reason:
- UI replacement architecture
- Easier to migrate between UI kits
- Less technical debt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Reproducibility
&lt;/h2&gt;

&lt;p&gt;All tests are available and reproducible:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub Repository:&lt;/strong&gt;&lt;br&gt;
👉 &lt;a href="https://github.com/optimajet/formengine/tree/master/community/examples/bundle-size" rel="noopener noreferrer"&gt;github.com/optimajet/formengine/tree/master/community/examples/bundle-size&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Full Report:&lt;/strong&gt;&lt;br&gt;
👉 &lt;a href="https://formengine.io/documentation/bundle-size-comparison" rel="noopener noreferrer"&gt;formengine.io/documentation/bundle-size-comparison&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to Run Yourself:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/optimajet/formengine.git
&lt;span class="nb"&gt;cd &lt;/span&gt;formengine/community/examples/bundle-size
npm &lt;span class="nb"&gt;install
&lt;/span&gt;npm run build
npm run analyze
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;What You'll Get:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bundle size report&lt;/li&gt;
&lt;li&gt;Chunk visualization&lt;/li&gt;
&lt;li&gt;Duplicate packages detection&lt;/li&gt;
&lt;li&gt;Tree-shaking analysis&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What's Next?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Try It Yourself
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;RJSF:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;📚 &lt;a href="https://rjsf-team.github.io/react-jsonschema-form/" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💻 &lt;a href="https://github.com/rjsf-team/react-jsonschema-form" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;FormEngine:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;📚 &lt;a href="https://formengine.io/documentation" rel="noopener noreferrer"&gt;Documentation&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;💻 &lt;a href="https://github.com/optimajet/formengine" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Give Feedback
&lt;/h3&gt;

&lt;p&gt;If you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Found errors in tests&lt;/li&gt;
&lt;li&gt;Want to add new scenarios&lt;/li&gt;
&lt;li&gt;Disagree with conclusions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Write to us:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Let us know what you think in the comments 👇&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/optimajet/formengine/issues" rel="noopener noreferrer"&gt;GitHub Issues&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="mailto:hello@optimajet.com"&gt;hello@optimajet.com&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Final Verdict
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;There's no universal winner.&lt;/strong&gt; And that's good! &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;RJSF&lt;/strong&gt; — excellent choice for quick start and JSON Schema purists&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FormEngine&lt;/strong&gt; — optimal for integration into existing projects with UI kits&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Choose based on your context, not marketing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's your experience with RJSF or FormEngine? Or are you using something else? Share in the comments! 👇&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;P.S. We're Optimajet, also making &lt;a href="https://workflowengine.io" rel="noopener noreferrer"&gt;Workflow Engine&lt;/a&gt; for processes and &lt;a href="https://workflowserver.io" rel="noopener noreferrer"&gt;Workflow Server&lt;/a&gt; for business automation.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>webdev</category>
      <category>frontend</category>
    </item>
    <item>
      <title>FormEngine Core is Now Open Source</title>
      <dc:creator>Optimajet Limited</dc:creator>
      <pubDate>Tue, 12 Aug 2025 14:22:39 +0000</pubDate>
      <link>https://dev.to/optimajet/formengine-core-is-now-open-source-n31</link>
      <guid>https://dev.to/optimajet/formengine-core-is-now-open-source-n31</guid>
      <description>&lt;p&gt;If you've ever spent hours wrestling with complex forms in React, struggling with validation, localization, or custom components, FormEngine is here to transform your workflow. This powerful tool combines an intuitive visual designer with a flexible, code-first library, enabling you to create any form, from simple to dynamic, data-driven ones, with ease. Born from our team's real-world challenges, FormEngine empowers solo developers and enterprise teams alike to save time and scale projects effortlessly. Curious about how it became a game-changer for developers? Read on to dive into the full story!&lt;/p&gt;

&lt;h2&gt;
  
  
  Your Ultimate Solution for Building Forms in React.
&lt;/h2&gt;

&lt;p&gt;Here’s a little story about how it all became possible. We began developing FormEngine in early 2023 to address our own internal needs, driven by the immaturity of the React form library ecosystem both in terms of backend-driven form generation and visual form designers. Our goal was to replace our outdated FormBuilder.dev, with a more modern and developer-friendly form builder built for React.&lt;/p&gt;

&lt;p&gt;After a thorough investigation, we hoped to find an open-source library we could build on something robust enough to support our team and integrate seamlessly into our commercial products: &lt;strong&gt;Optimajet Workflow Server&lt;/strong&gt; and form-related plugins for &lt;strong&gt;WorkflowEngine&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We evaluated the most popular MIT-licensed libraries and have great respect for React Hook Form, Formik, React Final Form, and SurveyJS, each of which has made a significant contribution to the React ecosystem.&lt;br&gt;
When tested against the strict internal requirements of the Optimajet development team, none could fully deliver the flexibility, integration depth, and scalability needed for our enterprise-grade use cases.&lt;/p&gt;

&lt;p&gt;One of the key requirements especially for large teams in big tech companies or custom software development firms is the ability to easily and quickly integrate custom components. We recognized that this was a common pain point across the industry, and we had the expertise to solve it.&lt;/p&gt;

&lt;p&gt;That insight led us to a bold decision: to build the best React-based FormBuilder from scratch-first and foremost, for ourselves. We surveyed our enterprise customers and small teams building business applications for workflow automation. Based on their feedback and requirements, we formed the foundation for what we believe to be an ideal form library one that supports code-first form creation in React, and serves as the engine behind a low or no-code visual form designer.&lt;/p&gt;

&lt;h3&gt;
  
  
  Here is the list of requirements and brief explanations that guided the Optimajet team when we started developing FormEngine Core.
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Lower learning curve:&lt;/strong&gt; Easily create forms using typed FormEngine Core functions, without writing components or learning complex React concepts. JSON representation of the form is also supported for configuration-driven use.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Built-in form validation:&lt;/strong&gt; Data validation works out of the box with no extra code. Required fields, error messages, and rules are defined directly in code or JSON. Easily integrates with third-party validation libraries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Built-in localization:&lt;/strong&gt; Forms are ready for multi-language support out of the box. Third-party localization libraries can be integrated if needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dynamic CSS and responsive layout support:&lt;/strong&gt; Forms automatically adapt to different devices and styles  no additional layout code needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Built-in actions:&lt;/strong&gt; Forms support actions like submit, reset, and external calls out of the box. Define only what you need in code or JSON and it’ll just work.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reusable forms across apps:&lt;/strong&gt; Cross-project compatibility just copy and use forms are easily portable between applications with minimal effort. A single JSON object contains the full structure, logic, styles, validation, and actions.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Programmatic form creation and dynamic generation:&lt;/strong&gt; Build or modify forms in real time using code or external data sources.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ready-to-use component library:&lt;/strong&gt; Includes built-in components and supports easy integration of custom ones. Get started fast without sacrificing flexibility.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Easy custom component integration&lt;/strong&gt;: Quickly define your own component by specifying its name, type, and props.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ready to use with popular frameworks:&lt;/strong&gt; Works seamlessly with Next.js, Remix, and other modern React stacks  no special setup needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High performance and lightweight:&lt;/strong&gt; Fast load times, smooth rendering, and minimal impact on app performance.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;On &lt;strong&gt;October 31, 2023&lt;/strong&gt;, we released &lt;strong&gt;FormEngine 0.0.13&lt;/strong&gt;  our new standalone commercial product. &lt;a href="https://formengine.io/documentation/release-notes#0013" rel="noopener noreferrer"&gt;Release notes →&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This marked the beginning of a journey to bring to life everything our development team had envisioned for the platform. And right from day one, the results confirmed we were on the right track.&lt;/p&gt;

&lt;p&gt;We delivered a complete, time-saving tool for development teams  something that works just as well for solo developers as it does for large projects. Whether you're building a few simple forms or managing hundreds or thousands of dynamically generated ones from a backend  &lt;strong&gt;FormEngine just works.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The initial sales were strong, and as demand grew, we even experimented with pricing tiers and product options to better understand what triggered the “Aha!” moment for our users.&lt;/p&gt;

&lt;p&gt;That moment where everything clicks  and the value is obvious.&lt;/p&gt;

&lt;p&gt;We’re still searching for a definitive answer to what exactly made the product such a commercial success, especially among enterprise teams. But one thing is clear: we hit a real need, and we’re excited to keep building on it. &lt;/p&gt;

&lt;p&gt;Thanks to the commercial licenses issued to our partners custom software companies we’ve been improving the &lt;strong&gt;FormEngine&lt;/strong&gt; libraries day by day, with one clear goal:&lt;/p&gt;

&lt;p&gt;To create the best React-based form solution on the market for developers and businesses who want powerful forms without the usual complexity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We give developers everything they need to build real, working forms  without the usual mess of extra tools, boilerplate, and setup.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.npmjs.com/package/@react-form-builder/core" rel="noopener noreferrer"&gt;@react-form-builder/core&lt;/a&gt; Community MIT Open Source Form Library for React  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.npmjs.com/package/@react-form-builder/components-rsuite" rel="noopener noreferrer"&gt;@react-form-builder/components-rsuite&lt;/a&gt; Form Components Library &lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.npmjs.com/package/@react-form-builder/designer" rel="noopener noreferrer"&gt;@react-form-builder/designer&lt;/a&gt; Premium Drag-and-Drop Form Builder, also known as the Visual Form Designer&lt;/p&gt;

&lt;h2&gt;
  
  
  Why FormEngine Core is Now Open Source?
&lt;/h2&gt;

&lt;p&gt;Many of our partners, who use FormEngine as part of their business process automation and approval workflow applications, asked us to open up the core Formengine  so they could deeply integrate it into their systems and even extend its functionality where needed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And now, after nearly two years of development and five major releases, the time has come.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;On 26 June 2025, we are proud of the quality, stability, and architecture of our code, and we are ready to share it. By open-sourcing the FormEngine Core library, we make this technology freely available to the global developer community, fostering innovation, transparency, and long-term adoption.&lt;/p&gt;

&lt;p&gt;Your support means the world to us, and we’d love for you to be part of this exciting new chapter for FormEngine.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;If you find value in what we’re building, consider giving us a ⭐️ on &lt;a href="https://github.com/optimajet/formengine" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;  it helps more amazing developers like you discover FormEngine Core.&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Open source thrives on collaboration, and we warmly welcome contributors who want to join us on this journey. Whether it’s contributing code, sharing ideas, or spreading the word, your involvement will &lt;a href="https://github.com/optimajet/formengine/discussions" rel="noopener noreferrer"&gt;help FormEngine, and our growing community thrive&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;With gratitude and excitement, &lt;strong&gt;The Optimajet Developers Team&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>opensource</category>
      <category>frontend</category>
      <category>webdev</category>
    </item>
    <item>
      <title>A True React Hook Form Alternative – FormEngine Core 4.0 Is Now MIT Licensed and Free! 🚀</title>
      <dc:creator>Optimajet Limited</dc:creator>
      <pubDate>Tue, 27 May 2025 18:06:46 +0000</pubDate>
      <link>https://dev.to/optimajet/a-true-react-hook-form-alternative-formengine-40-is-now-mit-licensed-and-free-1gke</link>
      <guid>https://dev.to/optimajet/a-true-react-hook-form-alternative-formengine-40-is-now-mit-licensed-and-free-1gke</guid>
      <description>&lt;p&gt;React developers, here's big news! On May 15, 2025, Optimajet released FormEngine Core 4.0, making essential libraries available under the permissive MIT license free even for commercial use. FormEngine is now the leading alternative to React Hook Form, especially for teams building complex, interactive forms.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why switch from React Hook Form to FormEngine?&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  ⚡️ Rapid and Simple Setup
&lt;/h2&gt;

&lt;p&gt;React Hook Form requires extensive manual setup of controllers, hooks, and validation logic. FormEngine simplifies this by leveraging intuitive, schema-based definitions.&lt;/p&gt;

&lt;h2&gt;
  
  
  🎨 Powerful Drag-and-Drop FormEngine Visual Designer
&lt;/h2&gt;

&lt;p&gt;Unlike React Hook Form’s code-only approach, FormEngine includes an intuitive visual editor, allowing instant form creation and modification, significantly speeding up development. &lt;em&gt;(Note: FormEngine Visual Designer is a paid component for commercial use; however, its full functionality is available for unlimited testing.)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🔌 Easy Custom Components Integration
&lt;/h2&gt;

&lt;p&gt;React Hook Form’s custom component integration can be cumbersome. FormEngine makes this seamless, simplifying component binding and custom logic implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  📱 Real-Time Form Previews
&lt;/h2&gt;

&lt;p&gt;Get instant visual feedback as you build forms. React Hook Form needs extra setup or third-party tools for similar functionality.&lt;/p&gt;

&lt;h2&gt;
  
  
  Built-In Component Library
&lt;/h2&gt;

&lt;p&gt;Unlike React Hook Form, FormEngine comes with a built-in library of ready-to-use components (@react-form-builder/components-rsuite), further accelerating development and reducing the need to create components from scratch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Completely Free and MIT Licensed
&lt;/h2&gt;

&lt;p&gt;FormEngine’s core libraries are now MIT-licensed and fully free, even for commercial use:&lt;/p&gt;

&lt;p&gt;📦 &lt;a href="https://www.npmjs.com/package/@react-form-builder/core" rel="noopener noreferrer"&gt;@react-form-builder/core&lt;/a&gt;&lt;br&gt;
📦 &lt;a href="https://www.npmjs.com/package/@react-form-builder/components-rsuite" rel="noopener noreferrer"&gt;@react-form-builder/components-rsuite&lt;/a&gt;&lt;br&gt;
📦 &lt;a href="https://www.npmjs.com/package/@react-form-builder/viewer-bundle" rel="noopener noreferrer"&gt;@react-form-builder/viewer-bundle&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  💡 Highlights of FormEngine Core 4.0:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;UI-Agnostic: Integrate effortlessly with UI libraries like MUI, Ant Design, shadcn/ui, and more.&lt;/li&gt;
&lt;li&gt;Framework-Friendly: Built-in support for Next.js, Remix, and framework-agnostic CDN deployment.&lt;/li&gt;
&lt;li&gt;Multi-Database Compatibility: Seamlessly use MySQL, PostgreSQL, MongoDB, SQLite, and more.&lt;/li&gt;
&lt;li&gt;Robust Validation: Powered by Zod, with extensible support for Yup, AJV, Superstruct, and Joi.&lt;/li&gt;
&lt;li&gt;Dynamic &amp;amp; Responsive: Create reactive, adaptive layouts with MobX-powered dynamic properties.&lt;/li&gt;
&lt;li&gt;Flexible Storage: Store forms as JSON or generate them programmatically.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;🎬 Watch the video to see FormEngine in action—start building your forms faster, smarter, and with greater ease than ever before!&lt;/p&gt;

&lt;p&gt;In this step-by-step tutorial, I'll walk you through building a simple React demo app using FormEngine. You'll see how quickly you can design, render, and manage forms — without writing endless custom code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install @react-form-builder/core
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Quickstart
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;viewWithCss&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@react-form-builder/components-rsuite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;buildForm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FormViewer&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@react-form-builder/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;simpleForm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;buildForm&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;errorType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;RsErrorMessage&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;container&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;RsContainer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;style&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;flexDirection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;row&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;children&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="nx"&gt;builder&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;firstName&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;RsInput&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;placeholder&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Enter your first name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;label&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;First Name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;validation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;required&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lastName&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;RsInput&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;placeholder&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Enter your last name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;label&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Last Name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;validation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;required&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;birthDate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;RsDatePicker&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;label&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Birth Date&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;oneTap&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;validation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;min&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;args&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1900-01-07T12:25:37.000Z&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;component&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;submit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;RsButton&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;children&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Submit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;color&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;blue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;appearance&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;primary&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;event&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;onClick&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;commonAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;validate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;args&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;failOnError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;customAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;onSubmit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;FormViewer&lt;/span&gt;
    &lt;span class="nx"&gt;view&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;viewWithCss&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;getForm&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;simpleForm&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt;
      &lt;span class="na"&gt;onSubmit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// submit the form to the backend&lt;/span&gt;
        &lt;span class="nf"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Form data: &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}}&lt;/span&gt;
  &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What you'll learn:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;How to install and set up the FormEngine Core Library&lt;/li&gt;
&lt;li&gt;Creating and editing forms using JSON&lt;/li&gt;
&lt;li&gt;Running your app and previewing form behavior&lt;/li&gt;
&lt;li&gt;Using the FormEngine Visual Designer to create forms&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  🌍 Help us grow the ecosystem, if you like the project:
&lt;/h2&gt;

&lt;p&gt;⭐ Star us on &lt;a href="https://github.com/optimajet/formengine" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;💬 Share feedback! Have feature requests or thoughts on the docs? Share them in the comments below!&lt;/p&gt;

&lt;p&gt;🔗 Mention &lt;a class="mentioned-user" href="https://dev.to/optimajet"&gt;@optimajet&lt;/a&gt; Formengine &lt;a href="https://x.com/" rel="noopener noreferrer"&gt;X / Twitter&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🚀 This is just the beginning — part two is on the way!
&lt;/h2&gt;

&lt;p&gt;We'll provide a detailed comparison between React Hook Form and FormEngine Core.&lt;/p&gt;

&lt;p&gt;📘 Docs, Live Demo &amp;amp; Examples: &lt;a href="https://formengine.io/documentation" rel="noopener noreferrer"&gt;formengine.io/documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;We’d love to address your specific questions, so please leave your questions in the comments, and we'll include the answers in our upcoming comparison!&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>webdev</category>
      <category>frontend</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Key differences between BPMN diagrams and Optimajet .NET Workflow Engine process schemes</title>
      <dc:creator>Optimajet Limited</dc:creator>
      <pubDate>Mon, 04 Nov 2024 16:06:28 +0000</pubDate>
      <link>https://dev.to/optimajet/key-differences-between-bpmn-diagrams-and-optimajet-net-workflow-engine-process-schemes-21ka</link>
      <guid>https://dev.to/optimajet/key-differences-between-bpmn-diagrams-and-optimajet-net-workflow-engine-process-schemes-21ka</guid>
      <description>&lt;p&gt;&lt;strong&gt;Element specialization&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In BPMN, there are a lot of elements that often have narrow specializations and are categorized into Tasks, Gateways, and Events, although other distinct elements exist as well. The Sequence flow is particularly significant and stands out.&lt;br&gt;
In Workflow Engine, there are only two types of elements in the scheme — Activities and Transitions. By combining the configurations of these two elements, you can create Workflow Engine schemes that function similarly to the corresponding BPMN elements.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Activity is not a Task&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;At first glance, an Activity appears as a rectangle, similar to a Task, and it may seem like these elements are alike. However, they're actually quite different. An Activity can represent a Service Task, a Gateway, or even an Event. The main function of an Activity is to execute your code, but the overall behavior of the scheme (i.e., the direction and manner in which the process flows next) depends on the settings of the outgoing Transitions from the Activity.&lt;/p&gt;

&lt;p&gt;For example, if an Activity has Transitions triggered by Commands, it acts similarly to an Event-based Gateway; however, unlike a Gateway, the Activity can execute some code. If the Transitions from an Activity are configured to start parallel processes, then that Activity will behave like a Parallel Gateway. And so on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Transition is not a Sequence Flow&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;At first glance, Transition and Sequence Flow may seem like similar elements, as both represent arrows between elements on a diagram. However, they're actually quite different.&lt;/p&gt;

&lt;p&gt;In Workflow Engine, a Transition defines how and where the process execution will transition. For example, a process can move to the next state based on a Timer or a Command. What is set by events in BPMN is managed through transitions in Workflow Engine. Additionally, Transitions can be conditional, and access to them can be restricted to specific users or roles. Transitions also determine parallelism, which in BPMN is either set through Gateways or implicitly defined.&lt;/p&gt;

&lt;p&gt;In BPMN, however, a Sequence Flow only defines the direction of the transition. This element has almost no settings, except for flows coming out of exclusive gateways.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Parallelism difference&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Parallelism in BPMN and Workflow Engine operates on different, yet non-contradictory principles.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In BPMN, parallel execution is defined either explicitly, using a Parallel Gateway, or implicitly, for example, when multiple Sequence Flows emerge from a single Service Task or Event. In this case, it is considered that the process remains singular, but several tokens are introduced. This can lead to a situation where, if you don't introduce a merging element or remove these tokens, multiple tokens will continue during sequential process execution.&lt;/li&gt;
&lt;li&gt;In Workflow Engine, you can assume that there is always only one token within a single process, and parallelism is achieved by creating dependent processes (called subprocesses in Workflow Engine). These subprocesses depend on the process that spawned them, and you can retrieve a list of Activities where the parent process and all its child subprocesses are located, as well as manage the parent process and its subprocesses collectively. The creation and merging of processes are handled by transition settings. However, if this approach is unfamiliar, you can use the Parallel Gateway, which replicates the behavior of its BPMN counterpart.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Subprocesses in BPMN and Workflow Engine are completely different&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In BPMN, a Subprocess is merely a nested part of the main diagram that can be collapsed. It can't be reused and is primarily for aesthetic purposes. Workflow Engine has a similar feature called Inline Activity. This is a special activity that embeds another scheme into the current one. The embedded scheme can be used in multiple other schemes, allowing for reusability.&lt;/li&gt;
&lt;li&gt;In Workflow Engine, a subprocess is a dependent process, as mentioned earlier.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Workflow Engine provides real access control to Commands&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In Workflow Engine, Actors are part of the process, and you can set restrictions on command execution (similar to a Message Catch Event) by specific users directly within the scheme. BPMN doesn't offer such functionality explicitly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Execution ready approach&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A valid Workflow Engine scheme is always ready for execution and can be run on the Workflow Engine. In contrast, a valid BPMN diagram might just be an illustration, and no engine will necessarily be able to execute it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Ability to set the Process to any state&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In Workflow Engine, a running process can always be forcibly set to any of its states. BPMN doesn't offer such a capability.&lt;/p&gt;

&lt;p&gt;Armed with this knowledge, let's move on to exploring which BPMN elements are supported in Workflow Engine and how they’re implemented.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Configuring and using BPMN plugin&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can read about how to install, configure, and start using the BPMN Diagram Import Plugin in the .NET Workflow Engine in the &lt;a href="https://workflowengine.io/documentation/bpmn-plugin" rel="noopener noreferrer"&gt;official documentation.&lt;/a&gt;&lt;/p&gt;

</description>
      <category>bpmn</category>
      <category>dotnet</category>
      <category>csharp</category>
    </item>
    <item>
      <title>Introducing BPMN support in .NET Workflow Engine library</title>
      <dc:creator>Optimajet Limited</dc:creator>
      <pubDate>Mon, 04 Nov 2024 15:55:44 +0000</pubDate>
      <link>https://dev.to/optimajet/introducing-bpmn-support-in-net-workflow-engine-library-4o71</link>
      <guid>https://dev.to/optimajet/introducing-bpmn-support-in-net-workflow-engine-library-4o71</guid>
      <description>&lt;p&gt;Many .NET developers, during the POC process, requested that we add the ability to import BPMN schemas into our WorkflowEngine. In an new &lt;a href="https://workflowengine.io/documentation/release-notes/workflow-engine/#breaking-changes" rel="noopener noreferrer"&gt;update&lt;/a&gt;, Optimajet's Workflow Engine now introduces foundational BPMN support, making it easier for .net developers to work with familiar process elements and streamline workflow designs. While Workflow Engine is not a dedicated BPMN engine, this new capability bridges some gaps by enabling users to work with BPMN elements, enhancing compatibility and efficiency for process modeling.&lt;/p&gt;

&lt;p&gt;Workflow Engine is not a BPMN engine, so full compliance with the BPMN standard isn't achievable. However, the process execution principles in Workflow Engine align with those of BPMN. Consequently, BPMN support in Workflow Engine is grounded in two key aspects:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;BPMN Elements in Workflow Engine Scheme:&lt;/strong&gt; We have added basic BPMN elements to Workflow Engine so that when a BPMN diagram is imported, familiar elements remain, making it clear where attention should be focused. Some of these elements are useful on their own, such as the Parallel Gateway, which can be beneficial for creating and merging subprocesses in Workflow Engine in a simpler and more understandable way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;BPMN Import:&lt;/strong&gt; You can import a BPMN diagram, and it will be converted into a Workflow Engine scheme. A detailed log and comments will indicate what is unsupported or only partially supported in the current implementation.&lt;br&gt;
The structure of this section will be as follows. First, we will describe the differences between BPMN diagrams and Workflow Engine process schemes. Then, we will review which BPMN diagram elements are supported in Workflow Engine and how they are implemented. Finally, we will explain how to integrate BPMN import into an application running Workflow Engine and how to customize this import process.&lt;/p&gt;

&lt;h2&gt;
  
  
  BPMN elements support in Workflow Engine
&lt;/h2&gt;

&lt;p&gt;The BPMN plugin for Workflow Engine currently supports only the most essential BPMN elements, with new functionalities being progressively added. Here’s an overview of the supported and partially supported elements:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tasks&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Generic Task - Converted into a standard Activity.&lt;/li&gt;
&lt;li&gt;Service Task - Transformed into a specialized Activity based on the values of attributes like &lt;code&gt;camunda:topic&lt;/code&gt; and &lt;code&gt;camunda:delegateExpression&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Receive Task - Supported, with an outgoing transition triggered by a Command.&lt;/li&gt;
&lt;li&gt;User Task. Not supported yet; support will be added after the release of the plugin integrating Workflow Engine with forms.&lt;/li&gt;
&lt;li&gt;Business Rule Task. Not supported; will be converted into a standard Activity.&lt;/li&gt;
&lt;li&gt;Manual Task. Not supported; will be converted into a standard Activity.&lt;/li&gt;
&lt;li&gt;Script Task. Not supported; will be converted into a standard Activity.&lt;/li&gt;
&lt;li&gt;Send Task. Not supported; will be converted into a standard Activity.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Gateways&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Exclusive Gateway and Parallel Gateway - Supported.&lt;/li&gt;
&lt;li&gt;Event-Based Gateway - Supported and converted into an Activity with transitions triggered by corresponding events.&lt;/li&gt;
&lt;li&gt;Inclusive and Complex Gateways - Not supported and are currently converted into standard Activities.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Events&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start Events - Generic Start Event is supported, with partial support for Message and Timer types.&lt;/li&gt;
&lt;li&gt;End Events - Generic and Terminate End Events are supported.&lt;/li&gt;
&lt;li&gt;Boundary Events - Partially supported; Message and Timer Boundary Events are converted into transitions with Command and Timer triggers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Other Elements&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Subprocesses and Pools - Converted to Inline Activities or separate workflow schemes.&lt;/li&gt;
&lt;li&gt;Call Activities and Lanes - Not supported; Lanes are ignored due to no equivalent grouping method in Workflow Engine.&lt;/li&gt;
&lt;li&gt;Parallelism&lt;/li&gt;
&lt;li&gt;In BPMN diagrams, implicit parallelism is converted to explicit parallelism in Workflow Engine, using dashed lines to mark the start of subprocesses and dash-dotted lines for their completion.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Feedback&lt;/strong&gt;&lt;br&gt;
Since BPMN support is an evolving feature, your feedback on the BPMN elements you need is invaluable to us. Please let us know in the comments below which elements are critical to your workflows, so we can prioritize their implementation in future releases. We will gradually add new BPMN elements based on requests from .NET developers who have chosen Workflow Engine as the workflow library for their business applications.&lt;/p&gt;

</description>
      <category>bpmn</category>
      <category>dotnet</category>
      <category>csharp</category>
    </item>
    <item>
      <title>Maximizing Hardware Utilization with Parallelism in Workflow Subprocesses Using Optimajet Workflow Engine</title>
      <dc:creator>Optimajet Limited</dc:creator>
      <pubDate>Wed, 11 Sep 2024 10:31:13 +0000</pubDate>
      <link>https://dev.to/optimajet/maximizing-hardware-utilization-with-parallelism-in-workflow-subprocesses-using-optimajet-workflow-engine-4adb</link>
      <guid>https://dev.to/optimajet/maximizing-hardware-utilization-with-parallelism-in-workflow-subprocesses-using-optimajet-workflow-engine-4adb</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In today's fast-paced digital landscape, businesses demand agility, scalability, and high performance from their software solutions. Workflow engines play a pivotal role in orchestrating tasks and automating processes, ensuring that everything runs smoothly. But when these processes become more complex and resource-intensive, how can workflow engines scale efficiently and stay responsive? The answer lies in &lt;strong&gt;threads&lt;/strong&gt;. Examples of schemas using &lt;strong&gt;subprocesses&lt;/strong&gt; in different workflows are described in detail in the &lt;a href="https://workflowengine.io/documentation/execution/subprocesses" rel="noopener noreferrer"&gt;official documentation of the Workflow Engine&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;However, in this article, we will try to explain complex things in simple terms. We'll explore what threads are in the context of the Optimajet Workflow Engine and how they can dramatically enhance efficiency, enabling smoother execution and more responsive workflows.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Parallelism in Workflow Subprocesses?
&lt;/h2&gt;

&lt;p&gt;In modern software systems, the need to optimize for both performance and resource efficiency has become a critical challenge. One of the most powerful techniques for achieving this is leveraging parallelism within subprocesses when building workflow schemas. By running multiple subprocesses concurrently, you can unlock higher performance and make full use of your hardware’s processing power. Optimizing workflows in this way can dramatically improve system efficiency, especially when dealing with complex workflows that involve multiple independent tasks. Parallelism refers to the ability to execute multiple independent or semi-independent subprocesses simultaneously. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh7wbe7q1ls5zjxmh777j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fh7wbe7q1ls5zjxmh777j.png" alt="Image description" width="591" height="322"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the context of workflow automation with Optimajet Workflow Engine, this means that different stages of a workflow can be run in parallel as Subprocesses, rather than waiting for each one to finish before starting the next. This improves efficiency, reduces execution time, and allows your workflows to handle more tasks concurrently.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Are Threads in a Workflow Engine?
&lt;/h2&gt;

&lt;p&gt;In simple terms, threads are independent sequences of execution within a larger process. In a multi-threaded environment, multiple tasks or operations can run simultaneously, each in its own thread. This allows for parallel processing, where multiple parts of a workflow can be executed at the same time rather than sequentially.&lt;/p&gt;

&lt;p&gt;Within the Optimajet Workflow Engine, threads enable you to break down a workflow into parallel paths of execution. These paths can run independently or concurrently, meaning that tasks that don’t depend on each other can proceed without waiting for others to complete. This parallelism can significantly boost performance and efficiency, especially in complex workflows where multiple independent tasks need to be handled simultaneously.&lt;/p&gt;

&lt;h2&gt;
  
  
  Threads and Their Role in Parallelism
&lt;/h2&gt;

&lt;p&gt;At the core of parallelism is the concept of threads. A thread is a lightweight unit of execution that can run code independently of other threads. In modern multi-core processors, threads allow you to take full advantage of the hardware by distributing work across different cores.&lt;/p&gt;

&lt;p&gt;In the Optimajet Workflow Engine, subprocesses within a workflow can be split into multiple threads. However, unlike some systems that automatically handle thread allocation, Optimajet requires developers to configure thread distribution manually when designing the workflow schema. This gives developers full control over how tasks are distributed across threads, ensuring that workflows are tailored to specific use cases and hardware environments.&lt;/p&gt;

&lt;p&gt;By using threads, developers gain several important benefits for efficiency, performance, and flexibility, which make thread-based parallelism an essential tool for optimizing workflows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefits of Using Threads in Workflow Schemes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Parallelism and Efficiency
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Benefit:&lt;/strong&gt; Threads allow for the parallel execution of tasks that can be performed simultaneously, meaning that workflows can handle multiple operations at once.&lt;br&gt;
&lt;strong&gt;Why Use It:&lt;/strong&gt; If you have tasks that don’t depend on each other—like sending notifications while processing data—threads can significantly speed up the workflow by reducing idle or waiting time.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Better Resource Utilization
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Benefit:&lt;/strong&gt; Threads make better use of system resources, particularly in multi-core processors. Instead of running tasks sequentially on a single CPU core, threads can distribute tasks across multiple cores for more efficient processing.&lt;br&gt;
&lt;strong&gt;Why Use It:&lt;/strong&gt; For workflows handling large datasets, high-volume tasks, or I/O operations (like API calls or database queries), threads maximize throughput by fully utilizing your system’s computing power.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Concurrency and Responsiveness
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Benefit:&lt;/strong&gt; Threads allow workflows to continue processing while waiting for external events (e.g., user input, network responses). This keeps the workflow responsive instead of stalling.&lt;br&gt;
&lt;strong&gt;Why Use It:&lt;/strong&gt; In complex workflows involving long-running tasks, threads prevent bottlenecks by keeping the rest of the workflow active.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Asynchronous Processing
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Benefit:&lt;/strong&gt; Threads enable asynchronous execution, meaning tasks can be initiated and the workflow can move forward without waiting for them to complete, revisiting them once results are ready.&lt;br&gt;
&lt;strong&gt;Why Use It:&lt;/strong&gt; This is particularly useful when interacting with external services or databases. Instead of halting the workflow, other operations can proceed, making the entire process more efficient.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Scalability
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Benefit:&lt;/strong&gt; Threads help workflow engines scale by handling large numbers of simultaneous operations. This ensures that as workflows grow in complexity, they can split the workload across multiple threads and execute them concurrently.&lt;br&gt;
&lt;strong&gt;Why Use It:&lt;/strong&gt; For businesses with growing demands, thread-based parallelism ensures that workflows can handle larger volumes of tasks or users without degrading performance.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Load Balancing
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Benefit:&lt;/strong&gt; In distributed systems, threads can help balance the load by distributing tasks across multiple systems or servers, preventing any one system from being overloaded.&lt;br&gt;
&lt;strong&gt;Why Use It:&lt;/strong&gt; When scaling workflows to handle multiple users or requests, thread-based processing distributes tasks evenly, avoiding overloads in certain parts of the system.&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Improved User Experience
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Benefit:&lt;/strong&gt; By performing background operations on separate threads, workflows can maintain a smoother, more responsive interface for users.&lt;br&gt;
&lt;strong&gt;Why Use It:&lt;/strong&gt; For workflows that involve user interaction (e.g., form submissions, approvals), threads allow background processing to occur without affecting the front-end experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  8. Concurrency Control
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Benefit:&lt;/strong&gt; Workflow engines utilizing threads provide mechanisms to manage concurrent processes, ensuring that shared resources aren’t corrupted due to conflicting operations.&lt;br&gt;
&lt;strong&gt;Why Use It:&lt;/strong&gt; When multiple threads need to access or modify shared data, thread-based concurrency control ensures safe access, avoiding race conditions and data corruption.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Optimajet Workflow Engine Manages Threads
&lt;/h2&gt;

&lt;p&gt;Unlike some workflow engines that automatically distribute tasks across threads, the Optimajet Workflow Engine requires developers to manually configure thread assignment within the workflow schema for subprocesses.&lt;br&gt;
Here’s how it works:&lt;/p&gt;

&lt;h3&gt;
  
  
  Manual Thread Assignment
&lt;/h3&gt;

&lt;p&gt;In the Optimajet designer, developers define which subprocesses should run in parallel and manually specify how they will be distributed across threads. This allows for more control over the threading model, making it possible to tailor workflows based on specific system requirements and workloads.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foijrq8mvo7we3772p7pb.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foijrq8mvo7we3772p7pb.jpg" alt="Image description" width="800" height="503"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Task Scheduling by Design
&lt;/h3&gt;

&lt;p&gt;The manual assignment of threads ensures that developers have full control over the scheduling of parallel subprocesses. While this requires some upfront design, it allows for more optimized performance as each task can be carefully scheduled based on the system’s capabilities.&lt;/p&gt;

&lt;h2&gt;
  
  
  Practical Example
&lt;/h2&gt;

&lt;p&gt;Imagine a workflow designed to process a customer order. This workflow may include subprocesses like validating the payment, checking inventory, generating shipping labels, and sending notifications to the customer. In a sequential workflow, each subprocess would run one after the other, increasing the time it takes to complete the order.&lt;/p&gt;

&lt;p&gt;By using &lt;strong&gt;Optimajet’s parallelism&lt;/strong&gt; and manually assigning threads:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Payment validation runs on one thread.&lt;/li&gt;
&lt;li&gt;Simultaneously, inventory checking runs on another thread.&lt;/li&gt;
&lt;li&gt;While these are happening, shipping label generation and notification sending can run on other threads.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The result is a much faster order processing time, as independent tasks are executed in parallel, fully utilizing the CPU cores. In this scenario, the system is able to handle more orders per minute, improving throughput and customer satisfaction.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Parallelism in workflow subprocesses, combined with manual thread assignment in Optimajet Workflow Engine, unlocks the full potential of your hardware. By distributing tasks across multiple threads, you can maximize CPU utilization, reduce latency, and increase throughput. Optimajet’s support for manual threading ensures that developers have the flexibility to optimize workflows for specific use cases and hardware environments.&lt;/p&gt;

&lt;p&gt;If your workflows are still running sequentially, it’s time to explore the power of parallelism. With Optimajet, you can build faster, more efficient workflows that scale effortlessly with your system’s needs.&lt;/p&gt;

</description>
      <category>parallelism</category>
      <category>dotnet</category>
      <category>workflow</category>
      <category>csharp</category>
    </item>
  </channel>
</rss>
