Skip to content

Blog

In this webinar we dive into different delivery models supported by Jmix.The webinar explored how product teams can efficiently build and deliver scalable, maintainable digital products using the Jmix platform. It focused on solving common problems in B2B software delivery like managing endless client customizations, code forks, and growing maintenance costs.

Viktor Fadeev, Jmix Product Manager, introduced Jmix as a rapid app development platform for Java teams. It combines a powerful framework, visual Studio plugin for IntelliJ, and a marketplace of ready-made add-ons. With Jmix, teams can build digital products faster, with a clear structure and using full-stack tools.

The session covered three key delivery models supported by Jmix:

**Extension Model**

Package core functionality into reusable add-ons, and allow client-specific extensions without changing the base code. Great for niche products where each client has different needs.

**SaaS Model**

Use Jmix’s built-in multi-tenancy features to deliver one shared application for many clients. Ideal for scaling across SMBs. But as the product grows, you’ll need to manage challenges like performance, database scaling, and customization limits.

**Self-Hosted Model**

Perfect for industries with strict regulations. Deliver isolated deployments with full control and source code access. Jmix’s composite projects help split large systems into manageable modules, reducing duplication and improving development speed.

**Key Takeaways**

– “Copy-paste and pray” doesn’t scale – modular delivery is essential for long-term success.
– Jmix helps avoid code forks with clear boundaries between core logic and client-specific features.
– Multi-tenancy is available out-of-the-box and works well for SaaS models with minimal customization.
– Composite projects simplify self-hosted delivery, especially for complex enterprise clients.
– Early consulting and training reduce risk – get architecture right from the start.

**Summary**

Jmix offers the tools and structure needed to quickly deliver robust, scalable digital products. Whether you’re targeting niche clients, growing SaaS, or serving regulated industries, picking the right delivery model makes all the difference.


Source: Webinar Recap: Choosing the Right Delivery Strategy with Jmix

Overview of the new features and important changes of the Jmix 2.6 feature release.We are pleased to announce the release of Jmix 2.6, which includes new features, enhancements, and performance improvements. This release brings significant updates to Jmix Studio, introduces new UI components, and boosts productivity with smarter tools and integrations.

Below is a quick overview of Jmix 2.6’s key features.

## Studio Improvements

### Jmix AI Assistant

The Jmix AI Assistant is now integrated into Jmix Studio tool window. This assistant shares chat history with the web-based version, enabling seamless transitions between Studio and web browser, so you can pick up right where you left off.

![ai-assistant]({{strapiUrl}}/uploads/Pasted_image_20250626132808_b1922b3c2a.png)

### New Code Snippets

Jmix 2.6 adds over 20 new UI-related code snippets, covering notifications and dialogs, opening views and fragments, asynchronous execution, and API examples. These snippets make it faster and easier to implement common UI patterns in your projects.

### Moving Views

Relocating views is now simpler with the _Move View_ context menu action in the Jmix tool window. This feature moves both the Java controller and XML descriptor together, automatically updating message keys in the message bundle. Additionally, when moving a Java controller or XML descriptor in the Project tool window, Studio prompts you to relocate the corresponding file and update message keys.

### Scaffolding Renderers

Generating renderers for UI components, such as `dataGrid` columns, is now more intuitive. Studio offers a wizard to scaffold `ComponentRenderer`, `TextRenderer`, or an empty handler method, simplifying the creation of custom UI renderers.

### Replacing Strings with Localized Messages

A new _Replace with localized message_ intention action, available in both Java and XML code, lets you quickly replace string literals with localized messages from the message bundle.

For example, imagine that you have the following code in a view descriptor:
“`java
@Subscribe
public void onInit(final InitEvent event) {
someLabel.setText(“Hello World”);
}
“`

Put cursor on the “Hello World” string and press `Alt-Enter`. Select *Jmix: Replace with localized message* action, and Studio will show a dialog for creating a localized message. After entering the message key and clicking *OK* the code will be changed to the following:

“`java
@ViewComponent
private MessageBundle messageBundle;

@Subscribe
public void onInit(final InitEvent event) {
someLabel.setText(messageBundle.getMessage(“label.text”));
}
“`

### Lombok Support

Studio now supports `@Getter` and `@Setter` annotations on entities and `@RequiredArgConstructor` on Spring beans, avoiding redundant code generation. It also warns developers about using `@EqualsAndHashCode` or `@Data` annotations on entities, which can cause issues due to incorrect equals/hashCode implementation.

### Performance on Large Projects

Performance has been significantly enhanced for large projects. The Jmix tool window’s project tree and resource role designer now operate smoothly, even in projects with over 1,000 entities.

## New UI Components and Features

### Switch Component

Introducing the new **Switch** component, which allows users to toggle between two states (e.g., on/off or true/false). Designed to resemble a physical toggle switch with a sliding handle, it adds a modern touch to your UI.

### Tabbed Application Mode Improvements

The **Tabbed Application Mode** add-on is now production-ready with several enhancements:

– The `mainTabSheet` component is explicitly defined in the main view layout, supporting actions via the tab context menu or keyboard shortcuts and ability to drag-and-drop tabs.
– The `@TabbedModeViewProperties` annotation for defining view parameters in tabs.
– Preserved UI state and firing `UIRefreshEvent` on web page refresh.

![Pasted image 20250626164513.png]({{strapiUrl}}/uploads/Pasted_image_20250626164513_50c3430c60.png)

### Autocompletion in CodeEditor

The `codeEditor` component now supports autocompletion for specific language modes or custom suggestion handlers.

### HorizontalLayout Slot Placement

The `hbox` component now supports adding components to `start`, `center`, or `end` alignment slots, offering simplified component positioning within the `HorizontalLayout`. For example:

“`xml











“`

![Pasted image 20250626174227.png]({{strapiUrl}}/uploads/Pasted_image_20250626174227_afe4fec970.png)

### Export/Import of Message Templates

The **Message Templates** add-on now supports _Export_ and _Import_ actions, enabling easy transfer of templates between applications.

## REST DataStore Enhancements

The REST DataStore add-on simplifies invoking remote services exposed via REST API. Now you only need to create an interface mirroring service methods and annotate it with `@RemoteService`.

The add-on now includes the `restds_RestOidcAuthenticator` bean that allows you to use an external authentication provider (for example Keycloak) when integrating applications.

## Masquerade UI Testing Library

Jmix 2.6 introduces Masquerade, an end-to-end UI testing library tailored for Jmix applications. Built on Selenium WebDriver and Selenide, Masquerade simplifies testing by providing convenient wrappers and streamlining access to web element functions.

## Updated Dependencies

The Jmix 2.6 release includes updates to major dependencies:

– Spring Boot has been updated to version 3.5.
– Vaadin has been updated to version 24.7.

These updates ensure that Jmix continues to be built on a modern, secure, and performant foundation.

## Future Plans

The next feature release is expected in October 2025. We will focus on the following functionality:

– Grouping DataGrid component
– UserMenu component
– Data model visualization
– SAML add-on
– Ability to define reports in Java code
– Reverse engineering: generate attributes from database columns for already mapped entities

## Conclusion

Jmix 2.6 introduces powerful new features and enhancements designed to boost developer productivity and enrich application capabilities.

If you have a question, want to share feedback, or simply connect with others, join us on the forum or Slack.

A big thank you to everyone in the community for your valuable contributions. We hope Jmix 2.6 brings even more success to your projects!
Source: Jmix 2.6 Is Released

In this article, we talk about process variables: what they’re for, how they differ from programming variables, and how scope works.This article continues the BPMN: Beyond the Basics series – a look at the practical, less-discussed aspects of working with BPMN for developers. Today, we’ll talk about process variables: what they’re for, how they differ from programming variables, and how scope works. At first glance, it might seem like there’s nothing special about them, but if you dig below the surface, there’s more nuance than expected. In fact, we couldn’t fit it all into one piece article, so we’re splitting this topic into two parts.

## Data in a Process

Process modeling traditionally begins with actions: approve a document, submit a request, sign a contract, plant a tree, deliver a pizza. Data is often left in the background, as if the performer intuitively knows where to get the right document or which pizza to deliver.

That works in human-centered, descriptive processes. People are expected to understand context, navigate loosely defined inputs, and follow general instructions. That’s why process models often resemble enhanced job descriptions more than software logic.

But when we move into automation, especially full automation, the game changes. A process without people must be **explicit about how it handles data**. It becomes not just a chain of steps, but a **data processing mechanism**. And if you want that mechanism to run fast and reliably, you need to understand how data is passed in, stored, transformed, and retrieved.

In short, a business process without data is like a horse without a cart — it might go somewhere, but it’s not carrying any value.

## Data-Centric Processes and BPM Engines

Even though classic processes like document flow and multi-step approvals are still important for many companies, the shift toward full automation is well underway. Gartner predicted that by 2025, 70% of organizations will have adopted structured automation—up from just 20% in 2021. And the whole workflow automation market? According to Stratis Research report, the workflow automation market is expected to top $45 billion by 2032, which shows just how much everyone wants to automate everything from start to finish.

Why the rush? It’s mostly about cutting down on mistakes, saving money, and speeding things up. Some studies (Gitnux) say automation can reduce errors by as much as 70% and lets people focus on more interesting, higher-value work. So, fully automated processes—where data processing and orchestration are front and center—are quickly becoming the new normal in digital transformation, not just a nice-to-have.

Let’s see how ready our BPM engines are for this. Spoiler: not very.

“BPMN does not provide a comprehensive data model. Data Objects and Data Stores are used to show that data is required or produced, but their structure is not defined.”

— “BPMN 2.0 Handbook: Methods, Concepts, and Techniques for Business Process Modeling and Execution” (2011)

“BPMN is not intended to model data structures or detailed data flows.”

— Bruce Silver, “BPMN Method and Style” (3rd Edition, 2016)

BPMN notation was originally created as a language for describing processes and does not include data models. Everything related to data in it is limited to so-called “`Data Objects“`, which only hint that some kind of data or documents are used in the process (judging by their icon). There is also the “`Data Store“`, which pretends to be a database or some information system, again based on its appearance.

![Picture1.jpeg]({{strapiUrl}}/uploads/Picture1_887fa84ab6.jpeg)

In essence, these are just graphical symbols. Their role is limited to informing the diagram reader that some data exists in the system and there is interaction with storage. There is no engine-level implementation behind them.

As a result, we have a situation where there are clear rules for modeling the process itself according to the BPMN 2.0 standard, which are implemented in a very similar way (if not identically) across engines. But there is no unified mechanism for working with data — each developer decides how to handle it on their own.

On the one hand, this is good — freedom! You can choose the optimal solution for your tasks. On the other hand, the lack of clear rules often leads to fewer than ideal data handling solutions in projects.

## Why Do We Need Process Variables?

So, at the BPMN model level, we don’t have data as such — the diagram describes the structure and logic of the process but does not operate directly with variables. However, when the process is executed, data becomes necessary: somewhere you need to save user input, somewhere to make a decision, and somewhere to send a request to an external system. All this data exists in the form of process variables, which are “attached” to each process instance and accompany it throughout its execution.

Broadly speaking, process variables fulfill four roles:

– Data transfer between steps
– Process flow control
– Interaction with the user
– Integration with external systems

![Picture2.png]({{strapiUrl}}/uploads/Picture2_7cebe27155.png)

Process variables help carry information through the entire process, from start to finish. For example, a user fills out a loan application form, and the data they enter (amount, term, loan purpose) is saved into variables. Then these values are used in service tasks, passed to gateways, and determine which branches should be activated. In one branch, a variable may be updated or supplemented and then passed further, for example, to a verification or notification task.

They also allow us to control the behavior of the process during execution. Suppose we have a variable called “`priority“`, calculated based on the application parameters. If, at the process start, it equals “high,” the task is automatically routed to a specific specialist; otherwise, it goes into a general queue.

When the process interacts with a user, variables become the link between the form and the process logic. They are used both to display data and to receive user input. If a variable was already set on a previous step — for example, “`userEmail“` — its value can be shown in the form. The user, in turn, fills in other fields, and their values are saved back into variables to be used later in the process. Thus, the form works as a “window” into the current execution context: everything the process knows at this point is available to the user, and everything the user enters remains in the process.

Finally, process variables are a communication channel with the outside world. When a service task calls a REST API, it can use variables as input parameters and save the response to a variable. This response can then be analyzed, logged, passed to another service, or displayed to the user.

## The Lifecycle of a Variable

Now let’s talk about how process variables are born, live, and end their lifecycle. To do that, we first need to look at how they are structured.

In BPM systems such as Camunda, Flowable, or Jmix BPM, process variables are objects that store not only their value but also metadata about themselves. In other words, they’re not simple variables like in Java or another programming language — they’re containers that hold data.

Why make it so complicated? Because a process can run for a long time — hours, days, or even months. That’s why the values of variables need to be stored in a database, so they can be retrieved later when needed. And if we write something to the database, metadata appears as well—it’s only logical.

### Creation and Persistence of Variables

Note: The examples in this section are based on the Flowable engine.

So, data has entered the process — for example, as a payload in the start message, in the form of a “`Map“`. What does the engine do next? First, it creates a process instance — “`ProcessInstance“` — and initializes its execution context. Then the engine automatically saves all passed variables into this context using the “`setVariable“` method. But it’s important to understand: the engine doesn’t just “store” values somewhere in memory. It wraps each variable according to its type into an internal entity called “`VariableInstanceEntity“`, making the variables immediately accessible throughout the process — in scripts, transition conditions, tasks, and so on.

Additionally, a developer can create a variable in code whenever needed, also using the “`setVariable“` method — including from Groovy scripts:

“`runtimeService.setVariable(executionId, “docStatus”, “APPROVED”); “`

As long as the process hasn’t reached a transaction boundary, no database writing occurs. The variable remains in an in-memory structure — a “`List“` within the “`ExecutionEntity“`. This is convenient: the next task or script can be used without hitting the database.

However, once the process hits a wait state — such as a message or signal event, timer, user task, event-based gateway, or asynchronous task — the transaction is committed, and all entities created or modified during the transaction are flushed to the database. This includes process variables, which are written to the “`ACT_RU_VARIABLE“` table.

![Picture3.png]({{strapiUrl}}/uploads/Picture3_861083b5f5.png)

If the variable type is a primitive, it is stored as-is in the corresponding field of the table. Non-primitive variables, on the other hand, are serialized before being saved — and stored either as strings or byte arrays.

### Table Fields (Translated from Russian)

| Field | Type | Purpose |
|—————|——————|———————————————————————————————————————————————-|
| `id_` | `varchar(64)` | Unique variable ID. Primary key of the table. |
| `rev_` | `integer` | Record version (used for optimistic locking when updating the variable). |
| `type_` | `varchar(255)` | Variable type (e.g., string, long, boolean, serializable, json, object, bytearray, etc.). Determines which value fields are used. |
| `name_` | `varchar(255)` | Variable name. |
| `execution_id_`| `varchar(64)` | ID of the specific execution the variable is linked to. |
| `proc_inst_id_`| `varchar(64)` | ID of the process the variable belongs to. Used for retrieving variables by process. |
| `task_id_` | `varchar(64)` | Task ID if the variable is scoped at the task level. |
| `scope_id_` | `varchar(255)` | Used only in CMMN. |
| `sub_scope_id_`| `varchar(255)` | Used only in CMMN. |
| `scope_type_` | `varchar(255)` | Scope type (bpmn, cmmn, dmn). Not actually used in practice. |
| `bytearray_id_`| `varchar(64)` | ID of the entry in the `act_ge_bytearray` table where the variable value is stored (if it’s a byte array or a serialized object). |
| `double_` | `double precision`| Variable value if the type is double. |
| `long_` | `bigint` | Variable value if the type is long, integer, short, or boolean (as 0/1). |
| `text_` | `varchar(4000)` | Variable value if the type is string, json, date, or uuid. May also hold serialized values as text. |
| `text2_` | `varchar(4000)` | Additional text field, e.g., for serialization format or extra parameters. May be used in JSON/XML serialization. |
| `meta_info_` | `varchar(4000)` | Metadata about the variable, such as object class (if it’s a serialized object), or other engine-relevant info. Not used in Jmix BPM. |

Once a variable is written to the “`ACT_RU_VARIABLE“` table, it becomes part of the process’s persistent state. This means that even if the server is restarted, the process can be restored and resumed — along with all its variables. At this point, the cache is also cleared, and the “`VariableInstanceEntity“` objects are removed from memory.

In some cases, however, you may want a variable **not** to be stored in the database, for example, intermediate calculation results that aren’t needed in later steps of the process, or sensitive data like passwords, authorization tokens, and similar. In such cases, variables can be declared **transient** and will be kept in memory only. But this is up to the developer — by default, all variables are persistent.

### Reading and Updating Variables

Now let’s take a look at how variable reading works.

![Picture4.png]({{strapiUrl}}/uploads/Picture4_f9233266e6.png)

After one transaction is successfully completed, the next one begins, and a new variable cache is created. Initially, this cache is empty — variables are not loaded by default. Only when a variable is actually needed does the engine execute a command like:

“`String status = (String) runtimeService.getVariable(executionId, “docStatus”); “`

First, the engine locates the corresponding “`ExecutionEntity“` using the given “`executionId“`. This is the **execution context** that holds variables associated with a specific active step of the process. If the variable is not yet in memory, the engine issues an SQL query to the “`ACT_RU_VARIABLE“` table. The retrieved object is then deserialized (if necessary), added to the “`ExecutionEntity“` cache, and returned to the calling code.

If you need not just the value but the full variable information including metadata, you can request a “`VariableInstance“` object:

“`VariableInstance statusVar = runtimeService.getVariableInstance(executionId, “docStatus”); “`

Keep in mind, though, that this is a **read-only** object. If you want to update the variable, you must call “`setVariable“` again. The new value will be written to the database during the next commit. Technically speaking, this is not an update, but rather the creation of a new variable with the same name.

And here’s a subtle point: the engine does not enforce type consistency. So, if the variable originally held a string, and you later assign a number to it, the engine will accept it without complaint. However, this may lead to issues later — for example, when accessing historical data or using the variable in other steps of the process.

### Deleting Variables

When a process (or execution) ends, its variables are deleted. That is, all entries in the “`ACT_RU_VARIABLE“` table associated with the specific “`executionId“` are removed.

A developer can also proactively delete a variable before the process finishes:

“`runtimeService.removeVariable(executionId, “largePayload”); “`

Normally, this isn’t necessary just for “clean-up” purposes — the engine handles that on its own.

However, there are situations where proactively removing variables can be useful. For example, when a variable contains a large amount of data — say, a JSON object several megabytes in size or a high-resolution image. Keep in mind, this data is stored in the database, not in the Java process memory — so we’re not talking about garbage collection here, but about reducing database load.

If a variable contains personal or sensitive data (like temporary passwords or one-time codes) and is no longer needed after use, it should be deleted.

Some variables are used only within a single step (for example, intermediate results). These can be removed after that step finishes to avoid confusion or accidental reuse.

To avoid dealing with deletion altogether, it’s often better to declare such variables as **transient** right from the start.

Transient means that the variable is temporary and not saved permanently (for example, not stored in a database or persisted between sessions). It exists only during the runtime or the current process and disappears afterward.

### Writing to History

A key principle is that historical records for variables are **not** created when the process finishes, but rather **at the moment the variable is set** (“`setVariable“`), if history tracking is enabled. This is controlled by the “`historyLevel“` parameter.

| historyLevel | Description | What Is Stored |
|————–|——————————|——————————————————————————–|
| `none` | History is completely disabled | Nothing |
| `activity` | Minimal history: tracks process activity | Process start/end, tasks, events |
| `audit` | More detailed history | Everything from `activity` + variables (latest value only) |
| `full` | Complete history, including changes | Everything from `audit` + all variable changes (`ACT_HI_DETAIL`) |


By default, the engine uses the “`audit“` level — a compromise between useful historical data and performance.

So, in most cases, history is enabled. When a variable is created, its value is also written to the ACT_HI_VARINST table. More precisely, a “`HistoricVariableInstanceEntity“` is created and inserted into that table when the transaction is committed.

If “`historyLevel = full“`, **every** change to the variable is also recorded in the “`ACT_HI_DETAIL“` table.

**Important Note**

BPM engines do not provide a unified mechanism for working with variables. Variables can appear anywhere — as a field in user form, as a payload in a message or signal, or declared in script code, Java delegates, or Spring beans.

All of this is entirely the developer’s responsibility. Your IDE won’t be able to help. That’s why extreme attentiveness is required. One day, you may want to fix a typo in a variable name — but there will be no way to automatically track down all the places where it’s used.

### Scope

Like regular variables, process variables have scope. But this concept works quite differently in BPM than in programming languages. Just accept it as a fact and don’t rely on intuition — it can easily mislead you.

In programming, a variable scope is defined lexically, — depending on the class, method, or block where it is declared. It doesn’t matter whether the language uses static typing, like Java, or dynamic typing, like Python.

Process variables are something entirely different, as Monty Python might say. Essentially, they are not just variables but runtime objects. Therefore, the lexical approach doesn’t apply here. And although you can declare variables in a BPMN model, it’s not a true declaration like in programming. It’s more like a description of intent — the engine doesn’t require these variables to exist until they are actually set.

For example, in Jmix BPM, you can define process variables in the start event. Such declarations are useful for documentation purposes, so anyone reading the model understands which variables are used. And if the process is started programmatically, explicitly listing the variables helps the developer know what parameters are needed to start it.

![Picture5.jpeg]({{strapiUrl}}/uploads/Picture5_6266afbb22.jpeg)

But they will not appear in the process by themselves. They must either be passed as parameters or created at some subsequent step using the setVariable method. Otherwise, if you try to access them, the system will throw an error stating that such an object does not exist.

As we discussed in the first part of this article, process variables are created as a result of calling the “`setVariable“` method. Their scope is determined by their “birthplace,” almost like citizenship — that is, the execution context in which they were created.

When a process instance starts, the engine creates a root execution context (the process instance). Then, as the process progresses, these contexts form a hierarchical structure. For example, when the flow encounters an embedded subprocess, a parallel gateway, an asynchronous task, and so on, a new execution context is created. Subsequently, child contexts arise relative to previous ones. Thus, execution contexts form a tree.

Accordingly, the scope of variables is defined by the position of their execution context within this tree. Variables created in a higher-level context are visible in all the lower levels beneath them.

Let’s take a process as an example and mark all its execution contexts:

![Picture6.png]({{strapiUrl}}/uploads/Picture6_3f23116a4d.png)

Then, represented as a tree, it will look like this:

![Picture7.jpeg]({{strapiUrl}}/uploads/Picture7_9e0bc84963.jpeg)

If we define the variable “`orderId“` at the top level of the process, it will be accessible everywhere. But a variable like “`discount“`, if it is set in the first parallel branch, will only be visible within its own execution context and cannot be accessed later outside of it. So, it’s important to plan variable declarations with their scope in mind.

A nested subprocess not only helps to structure execution logic but also creates a new scope — and this can actually be its more important feature.

A separate story applies to external subprocesses (call activities). Each such call is wrapped in its own execution context. That’s why in the second parallel branch we see another nested execution. But the external subprocess itself runs as a completely separate instance, and by default does not see variables of the parent process. You must explicitly map variables to pass them into the child process — and similarly map them back if needed.

If you have event subprocesses, each one lives in its own execution and waits to be activated. There are no special tricks here — it sees all process-level variables plus its own.

When a multi-instance task occurs on the path, first a common execution context is created (in our example — execution 2) which tracks all instances. Then each instance gets its own separate execution context. A common mistake here is when someone tries to write a variable at the top level from a specific instance — for example, in parallel document approvals. As a result, all approvers overwrite the same variable, and you only see the decision of the last approver. The key here is not to get confused by all these variables, which are often named the same.

This situation is resolved by local variables, which we will discuss below.

## Local Variables

If you set a variable in the usual way, it will be visible to all child executions. But if you use the method “`setVariableLocal“`, it will be “locked” within the current execution and won’t be visible outside of it, including in lower-level contexts.

Okay. But why would you need to guarantee that a variable is not passed down the hierarchy?

Actually, this isn’t the main purpose. Local variables help keep things organized in your process: when you declare a variable as local, you make sure it won’t accidentally overwrite a variable with the same name in a broader (global or parent) scope.

Returning to our approval example: when in each instance of the multi-instance subprocess we explicitly specify that the comment field and the document decision are local variables, the chance of confusion is reduced.

In general, local variables are a mechanism for isolation and error prevention rather than a functional necessity. They do not solve problems that couldn’t be solved otherwise, but they do it more safely and cleanly.

## Variable Shadowing

What if variables have the same names?

This can happen — you create a variable in a child execution context with the same name as one already presented in the parent. In this case, variable shadowing occurs — the parent variable becomes inaccessible in the current context, even though it still exists in the execution tree.

**How it works**

Each execution context contains its own set of variables. When accessing a variable via the method “`getVariable(String name)“`, the engine first looks for it in the current execution. If the variable is found — it is used, even if a variable with the same name exists at a higher level. Thus, the higher-level variable is “shadowed.”

“`// Somewhere at the start of the process
execution.setVariable(“status”, “CREATED”);

// Inside a task or subprocess:
execution.setVariableLocal(“status”, “PROCESSING”);

// What will a script or service see in this execution?
String currentStatus = (String) execution.getVariable(“status”); // “PROCESSING”

“`

Although the parent variable still exists, the child variable overrides it within the current execution. Once you exit the scope of the child context (for example, when the subprocess ends), the higher-level variable becomes visible again.

Variable shadowing can be useful when used correctly, but it also represents a potential source of errors. In some scenarios, it provides an advantage — for example, allowing you to temporarily override a variable without changing its original value. This is especially convenient in multi-instance constructs where each instance works with its own copy of data.

However, shadowing can lead to unexpected results if you are not sure which context, you are in. Debugging becomes more difficult: in the history, you may see a variable with the same name, but it’s not always clear at what level it was created or why its value differs.

To avoid such issues, it’s recommended to follow several guidelines. It’s better to use different variable names if they have different meanings or belong to different execution levels.

Also, consciously manage the context in which variables are created and avoid using “`setVariableLocal“` unless there is a clear need. When analyzing process state, it is helpful to check variables at the current and parent levels separately using “`getVariableLocal()“` and “`getParent().getVariable()“` to get the full picture.

## Types of Process Variables

As for variable types, their variety depends on the engine developer — as mentioned earlier, the specification does not define this, so each implementation does its own thing. Of course, there is a common set that includes primitive types — strings, numbers, boolean values, as well as dates. But even here there are differences — compare the two illustrations and see for yourself.

In Camunda, we have one set of data types, while in Jmix BPM (with the Flowable engine) it is somewhat different.

![Picture8.jpeg]({{strapiUrl}}/uploads/Picture8_d9511615d6.jpeg)

Regarding the basic types, this difference is insignificant and may only become apparent when migrating from one engine to another. But there are some interesting distinctions worth mentioning.

You’ve probably noticed that Camunda supports JSON and XML types. However, this is not a built-in feature of the engine itself — to work with them, you need a special library called **Camunda Spin**, designed for handling structured data within business processes. It provides a convenient API for parsing, navigating, and modifying data, as well as automatically serializing and deserializing data when passing it between tasks. This can be especially useful when processing responses from REST services, storing complex structures as variables, and generating XML/JSON documents.

![Picture9.jpeg]({{strapiUrl}}/uploads/Picture9_05ff60b6ad.jpeg)

In turn, Jmix BPM allows you to use elements of the Jmix platform’s data model as process variables — entities, lists of entities, and enumerated types (Enums). This is especially helpful when you need to manipulate complex business objects within a process that contains dozens of attributes. For example, applications, contracts, support tickets, and so on.

Entity Data Task — Accessing the Data Model from the Process

Jmix BPM includes a special type of task called the Entity Data task. With it, you can create new entity instances, modify them, and load individual entities or collections of entities obtained via JPQL queries directly into process variables right from the process. This is not an extension of the BPMN notation per se. Technically, these are just regular service tasks with a specific set of parameters.

Thus, you can model a process in a low-code style — using User tasks for user actions and Entity Data tasks for data manipulation. If no complex integrations or logic are required, this approach is often sufficient.

Let’s consider a hypothetical example. Suppose some data arrives. The system checks whether it relates to an existing customer order or not. Depending on the result, it executes one task or another; either creating a new Order entity or loading/finding an existing one. Then, an employee performs some work, and an Entity Data task updates the modified attributes of the entity.

![Picture10.jpeg]({{strapiUrl}}/uploads/Picture10_2478e58f17.jpeg)

Of course, a real process would be more complex — this diagram merely illustrates the concept of how you can use an Entity Data task to work with data.

## Limitations

This section outlines the limitations of process variables in different BPM products.

### Camunda

**String Length Limitation**

In Camunda, values of type String are stored in the database in a column of type (n)varchar with a length limit of 4000 characters (2000 for Oracle). Depending on the database and configured character encoding, this limit may correspond to a different number of actual characters. Camunda does not validate the string length — values are passed to the database “as is.” If the allowed limit is exceeded, a database-level error will occur. Therefore, it’s the developer’s responsibility to control the length of string variables.

**Context Size Limitation**

Although process variables are stored in a separate database table, in practice, there is a limit to the total amount of data associated with a process instance. This limit is not so much about the physical storage but rather the internal mechanisms of serialization, memory loading, transactional handling, and other engine internals. A typical safe threshold is around **3–4 MB** per process context. This includes serialized variables, internal references, events, and other metadata. The exact value depends on the DBMS, serialization format, and engine configuration.

Storing too many variables or large documents in the process context can lead to unexpected “`ProcessEngineExceptions“` due to exceeding the allowable size of a serialized object. Therefore, when working with large variables, it is recommended to stay well below this limit and conduct performance testing if needed.

In **Camunda 8**, there is a strict limit on the size of data (payload) that can be passed into a process instance. The total maximum size of all process variables is **4 MB**, including engine internals. However, considering overhead, the safe threshold is around **3 MB**.

### Flowable / Jmix BPM

**String Length Limitation**

Flowable handles strings a bit differently: if the length of a “`String“`-type variable exceeds 4000 characters, it is automatically assigned an internal type of “`longString“`. Its value is then stored as a byte array in the “`ACT_GE_BYTEARRAY“` table, while the “`ACT_RE_VARIABLE“` table contains a reference to it. As a result, Flowable does not impose any explicit limit on string length.

In theory, the length of a string variable is only limited by the Java maximum —
“`Integer.MAX_VALUE = 2,147,483,647“`
(roughly 2.1 billion characters).
However, in practice, the effective limit is determined by available heap memory.

**Entity List Size Limitation**

For variables of type “`Entity List“`, there is a constraint related to the way they are stored. When saved to the database, such variables are serialized into a string format like:

“`.”UUID”“` — for example:
“`
jal_User.”60885987-1b61-4247-94c7-dff348347f93″
“`

This string is saved in a text field with a maximum length of 4000 characters. As a result, the list can typically contain around **80 elements** before exceeding the limit. However, this restriction only applies at the point of database persistence — in memory, the list can be of any size.

**Context Size Limitation**

Flowable (and thus Jmix BPM) does not enforce a hard limit on the size of the process context. Still, it’s recommended to keep the context as small as possible, since a large number of process variables can negatively impact performance. Also, you might eventually run into limits imposed by the underlying database system.

## Process Variables in Groovy Scripts

Scripts in BPMN are often underrated, yet they are a powerful tool—especially lightweight, in-process logic. They’re commonly used to initialize variables, perform simple calculations, log messages, and so on. BPM engines typically support **Groovy** or **JavaScript** as scripting languages, with **Groovy** being more prevalent due to its concise syntax, native Java compatibility, and ease of use when working with process objects. The most important of these is the execution object, which represents the process context and allows you to work with process variables.

Your main workhorses are the familiar “`setVariable“` and “`getVariable“` methods, used to write and read process variables. However, there’s a feature that—while seemingly convenient—can lead to hard-to-diagnose bugs:

**process variables in Groovy scripts are accessible directly by name.**

That means you can reference them in expressions without explicitly reading them first:

“`amount = price * quantity “`

But here’s the catch:

**The assignment operator does not affect process variables.**

So, after that expression, the value of the amount process variable will **not** change. To actually update it, you must explicitly call “`setVariable“`:

“`execution.setVariable(“amount”, price * quantity) “`

This is because a process variable is part of the execution context, not just a regular Groovy variable—it must be handled explicitly.

To complicate things further, Groovy allows you to define **local script variables** on the fly. Since Groovy is a dynamic language, it will silently create a new script variable if one isn’t already defined. So, if you haven’t explicitly created the process variable amount, the following line will still work:

“`
amount = price * quantity
execution.setVariable(“amount”, amount)
“`

And there’s more to it! Even though Groovy doesn’t require it, **declaring variables explicitly** using def is considered best practice. It helps avoid subtle bugs:

“`
def amount = price * quantity

execution.setVariable(“amount”, amount)
“`

Now everything is clean and correct. Right? — Well, almost.

When your script task is marked as **asynchronous**, this convenient implicit access to process variables by name might break.

Consider the following line in an asynchronous script:

“`
execution.setVariable(“counter”, counter + 1L)
“`

You might get a confusing error like:

“`
groovy.lang.MissingPropertyException: No such property: counter for class: Script2
“`

This means the variable counter wasn’t available in the script context at execution time.
Why? Because engines like Flowable inject process variables into the script environment **automatically**, but for **asynchronous executions**, this may happen **too late**—after the script has already started running.

To avoid this issue, always **explicitly read** the variable at the start of the script:
“`
def counter = execution.getVariable(“counter”)
execution.setVariable(“counter”, counter + 1L)
“`
And just like that — no more exceptions!

## Best Practices

Working with process variables is a key part of building reliable business processes. Variables allow the process to “remember” data, pass it between tasks, and make decisions. However, without discipline, they can easily become a source of bugs—from subtle logic errors to critical failures. This section outlines proven practices to help you avoid common pitfalls and build a clean, predictable data model in your process.

1. **Use clear and unique variable names**
Choose meaningful and descriptive names. Avoid duplicates.
Good: orderApprovalStatus
Bad: status

2. **The fewer variables, the better**
Keep in mind that the process context isn’t unlimited. Avoid creating unnecessary variables. Even without hard size limits, bloated contexts hurt performance.
Avoid storing large documents or massive JSON structures directly—store them as files and keep only a reference in the process.

3. **Use transient variables for temporary data**
If data is only needed within a single action or expression, define it as “`transient“`. It won’t be saved to the database or show up in history.

4. **Be cautious with entity variables**
Many BPM platforms support storing complex objects (e.g. entities) in process variables. This is convenient for business logic involving entity attributes.
However, if you load an entity into a variable at the start of the process, and later display it in a form days later, can you be sure it hasn’t changed? — Definitely not.
Instead, store the entity’s **ID** as a variable and re-fetch it when needed.

5. **Serialization may surprise you**
When saving complex objects, the engine serializes them before writing to the DB. Not all Java objects can be stored—your object must either implement “`Serializable“`, or you must provide and register a custom serializer.
Also, serialization may behave differently in regular vs. asynchronous tasks, since async tasks run in the “`JobExecutor“` which has a different context.

6. **Link entities to processes**
Often, a process is started in relation to an entity—an order, document, customer request, etc. You may want to navigate from the entity to its process.
Here’s a simple trick: add a “`processInstanceId“` field to your entity. No more searching with complex API queries—just follow the ID.

7. **Don’t blindly pass all variables into a Call Activity**
It’s tempting to tick the box that passes all variables from the parent to the subprocess. But it’s better to explicitly map only the variables you need.
Otherwise, you risk data leaks or serialization issues.

8. **Configure history settings**
The more variables you have, the faster your history tables will grow. All BPM engines support history cleanup mechanisms—take time to configure them.
If you need to keep historical data, create a mechanism to export it from the process DB to your own storage.
Also, be mindful of sensitive data—like credentials or API keys. They might be safe during the process but later get dumped into history with all other variables. And history access might be less secure than the live process.
So, to be safe—**avoid storing sensitive variables in history**.

9. **Use local variables where appropriate**
Technically, you can manage without local variables. But using them helps keep things organized. A clear local variable reduces the chance of errors.
However, don’t overuse them. It’s not necessary to make every child context variable local—sometimes you need them to propagate downward.

10. **Avoid unnecessary variable shadowing**
Variable shadowing (redefining variables in nested contexts) is mostly useful in multi-instance activities.
Outside of that, it’s better to give variables unique names to prevent confusion.

11. **Document your variables**
BPM engines don’t manage variables, and IDEs typically don’t help with this either.
Maintain your own variable registry—describe what each variable is for and where it’s used.
This will make your processes easier to maintain in the long run.

## Conclusion

Managing process variables with care is essential for building robust, maintainable business processes. By following these best practices, you can avoid common pitfalls and ensure your processes remain reliable and easy to support.

Thoughtful variable management not only prevents bugs and performance issues but also makes your process models more transparent for everyone involved. In the end, a little discipline in how you handle variables goes a long way toward creating clean, predictable, and future-proof BPM solutions.
Source: Everything a BPM Developer Should Know About Process Variables

Starting July 1st, 2025, we are introducing an updated subscription model for Jmix. These changes reflect the feedback we’ve gathered from long-term users and our ongoing efforts to keep Jmix sustainable and aligned with real-world development needs.Starting **July 1st, 2025**, we are introducing an updated subscription model for Jmix. These changes reflect the feedback we’ve gathered from long-term users and our ongoing efforts to keep Jmix sustainable and aligned with real-world development needs.

The new structure improves clarity across tiers, lowers the entry barrier for advanced features, and better separates distinct use cases like process automation.

## What’s Changing — and Why

1. **“Free” becomes “Community”**
We’re renaming the Free plan to **Community**. This name better reflects the open-source nature of Jmix and the tools shared across the entire developer base. No changes to features or access.

2. **“RAD” becomes “Sprint”**
While RAD served its purpose for many years, we’re renaming it to **Sprint** to better reflect how most teams work today — fast, structured, and iterative. The feature set remains unchanged.

3. **«Enterprise» becomes more focused and accessible**
With BPM functionality now separated, the Enterprise plan is focused entirely on enterprise-grade development features such as **Maps**, **Kanban**, **WebDAV**, **Notifications**, and **UI Constraints**. Following this restructuring, the plan will be priced **25% lower for companies** and **30% lower for individual developers**.

4. **«BPM» becomes a standalone plan**
Process automation is a distinct application layer with its own architectural and operational needs. To better serve those use cases, we’ve moved all BPM-related functionality — including the engine, process forms, task panel, and admin tools — into a dedicated **BPM plan**, offered at the same pricing level as the former Enterprise tier.

## A Note on Pricing Context

Earlier this year, in **January 2025**, we introduced a moderate price adjustment to reflect platform growth and operating costs. **At that time**, the Enterprise tier included BPM and other advanced tools in a single bundle.

With the July restructuring, we’ve realigned each tier to specific use cases. As a result, the Enterprise plan has a narrower focus, and its pricing has been revised accordingly. These changes are not simply discounts, but a reflection of the updated scope of each plan.

## How These Changes Affect Existing Users

– **Free (now Community)** continue to have full access to Jmix’s open-source core — now under a name that better represents its purpose.
– **RAD (new Sprint) monthly subscribers** will see only a name change. Pricing and access remain unchanged.
– **RAD (new Sprint) annual subscribers** will be automatically moved to the new Enterprise plan and will retain their current RAD pricing until **July 1st, 2027**. This includes full access to all Enterprise features (excluding BPM), including upcoming add-ons like Group Data Grid (coming Fall 2025) and Tabbed Application Mode.
– **After the 2-year transition period**, these users will have the option to continue with **Enterprise at the standard rate**, or return to the **Sprint** plan.
– **Enterprise subscribers** will be upgraded to the new **BPM plan** automatically. No action is needed. Access to all BPM features will continue uninterrupted and pricing remains the same.

## Looking Ahead

These updates are part of our continued effort to keep Jmix competitive, sustainable, and aligned with the needs of Java teams building complex enterprise software. The clearer tier structure also allows us to deliver new features faster and more predictably across the platform.

We remain committed to helping you build and ship high-quality software — faster, with less overhead, and with tools that match the scale of your team.

**Jmix — Develop smart, not hard!**

Source: Jmix Subscription Plans Update: Clearer Structure, More Value — Effective July 1st, 2025

This article explores why upgrading to Jmix 2 is a strategic move for your development projects.Se stai ancora utilizzando Jmix 1, ora è il momento perfetto per migrare a Jmix 2. Costruito su uno stack tecnologico moderno, supportato attivamente e ricco di nuove funzionalità potenti, Jmix 2 offre vantaggi significativi rispetto al suo predecessore. Questo articolo esplora perché l’aggiornamento a Jmix 2 è una mossa strategica per i tuoi progetti di sviluppo, migliorando produttività, sicurezza ed esperienza utente, garantendo al contempo la futura compatibilità delle tue applicazioni.

(Note: I have only provided the Italian translation as requested.)

Source: Aggiorna a Jmix 2: Rendi i Tuoi Progetti Future-Proof

This article explores why upgrading to Jmix 2 is a strategic move for your development projects.If you’re still using Jmix 1, now is the perfect time to migrate to Jmix 2. Built on a modern, actively supported technology stack and packed with powerful new features, Jmix 2 offers significant advantages over its predecessor. This article explores why upgrading to Jmix 2 is a strategic move for your development projects, enhancing productivity, security, and user experience while future-proofing your applications.

## Modern Technology Stack for Enhanced Security and Performance

Jmix 2 is built on a cutting-edge technology stack, including Spring Boot 3 and Vaadin 24, which are updated with each Jmix feature release every four months. In contrast, Jmix 1 is tied to Spring Boot 2 and Vaadin 8, both of which are no longer officially supported. This means Jmix 1 is limited to critical bug fixes and select security patches, with some third-party dependency vulnerabilities unfixable due to incompatibility with newer versions.

With Jmix 2, regular dependency updates ensure your applications benefit from the latest security patches, reducing vulnerabilities and enhancing safety. Additionally, newer Java versions in Jmix 2 deliver improved performance and modern language features, enabling developers to write cleaner, more efficient code. This forward-looking approach ensures your applications remain secure, performant, and aligned with industry standards.

## Mobile-Friendly and Customizable UI with Vaadin 24

Jmix 2 leverages Vaadin 24 to deliver a mobile-friendly user interface out of the box. Unlike Jmix 1, which requires separate mobile applications or complex workarounds, Jmix 2 supports responsive layouts, allowing you to optimize your UI for mobile devices without additional development effort. This streamlines development and ensures a consistent user experience across desktops, tablets, and smartphones.

Moreover, Vaadin 24 provides greater control over your application’s look and feel. With direct access to DOM elements and straightforward CSS styling, customizing the UI is simpler than ever. Jmix 2 also includes Java wrappers for standard HTML elements like `div`, `span`, `p` and `hr`, making it easier to create tailored, visually appealing interfaces that align with your brand. Additionally, the frontend part of Jmix 2 is now based on the web components standard, significantly simplifying the integration of third-party JavaScript components and libraries, enabling developers to enhance their applications with a wider range of modern tools and functionalities.

## Enhanced Navigation and User Experience

Jmix 2 introduces standard browser navigation for opening views, aligning with familiar web browsing behaviors. Users can now open views in new browser tabs via the context menu and use deep links to access specific application views directly. For those who prefer the Jmix 1 approach of opening screens in internal tabs within a single browser tab, Jmix 2 offers the optional **Tabbed Application Mode** add-on, providing flexibility to suit different preferences.

## New Features and Improvements in Jmix 2

Jmix 2 introduces a range of powerful add-ons and functionalities that are absent in Jmix 1, empowering developers to build more sophisticated applications with less effort:

– **Kanban Add-on**: visualizes project workflows with a Kanban board component, using cards for tasks and columns for project stages.
– **Superset Add-on**: allows you to embed Apache Superset dashboards into your Jmix application views, enhancing data visualization capabilities.
– **UI Constraints Add-on**: manages UI component visibility and accessibility using declarative policies in resource roles, even for components not tied to the data model.
– **OpenID Connect Add-on**: simplifies external authentication with providers like Keycloak, mapping user attributes and roles to Jmix users seamlessly.
– **REST DataStore Add-on**: allows you to easily integrate external Jmix applications, accessing remote entities through the `DataManager` interface as if they were local, with full CRUD functionality.
– **Authorization Server Add-on**: provides authentication for REST APIs in compliance with OAuth 2.1, ensuring secure and standardized API access.
– **OpenAPI Integration in Studio**: configures OpenAPI client generators and automatically generates DTO entities, mappers, and services for integration with external REST APIs.
– **Data Repositories**: built on Spring Data, Jmix 2’s data repositories combine the simplicity of repository interfaces with advanced Jmix data access features like data access control, entity events and cross-datastore references.
– **Entity Comments**: lets you add comments to data model entities and attributes, improving documentation and collaboration.

Jmix 2 brings notable enhancements to existing features, streamlining development and improving usability:

– **Studio UI Preview**: unlike Jmix 1’s schematic previews, Jmix 2’s Studio shows views with real components and styles, closely mirroring the running application.
– **Hot Deployment Status**: a new icon in Studio indicates the hot deployment status of view controllers, descriptors, message bundles, and roles, keeping developers informed about the delivery of the latest changes in the source code to the working application.
– **UUIDv7 for Entity Identifiers**: Jmix 2 uses UUIDv7 for entity identifiers, significantly boosting database operation performance compared to Jmix 1.

## Closing the Gap: Grouping DataGrid Coming Soon

The only notable feature missing in Jmix 2 compared to Jmix 1 is the GroupTable. However, this will be addressed with the upcoming Grouping DataGrid, set for release in October 2025. Once implemented, Jmix 2 will surpass Jmix 1 in every aspect, making it the definitive choice for modern application development.

## Jmix AI Assistant and Growing Ecosystem

**Jmix AI assistant** is optimized for Jmix 2 development, offering superior guidance compared to Jmix 1. Additionally, Jmix 2 benefits from a rapidly expanding ecosystem of documentation, guides, learning courses, and code examples. Unlike Jmix 1, which is in maintenance mode with only critical updates, Jmix 2’s resources are continuously improved, providing developers with more comprehensive support. This growing knowledge base also enhances compatibility with third-party AI assistants, making Jmix 2 projects easier to develop and maintain.

## Future-Proof Your Development with Jmix 2

Jmix 2 is a dynamic, evolving platform that receives new features and improvements every four months, ensuring your applications stay current with the latest technologies. In contrast, Jmix 1 is in maintenance mode, receiving only critical fixes. By migrating to Jmix 2, you gain access to a modern, secure, and feature-rich framework that enhances developer productivity and delivers superior user experiences.
Source: Upgrade to Jmix 2: Future-Proof Your Projects

This article shares the story of Ondrej, a senior Java developer, who accelerated full-stack development using Jmix.In the world of software development, finding tools that simplify the process without sacrificing functionality is a game-changer. Ondrej, a seasoned Java developer with over 20 years of experience, shares his journey of discovering Jmix and how it transformed his approach to building full-stack applications. His story highlights the challenges of traditional development and the advantages of adopting Jmix for solo developers and teams alike.

The Challenges of Traditional Full-Stack Development

Ondrej’s career has been deeply rooted in Java, with extensive experience in both back-end and front-end technologies like React and Angular. However, he often faced significant hurdles when working on full-stack projects, especially as a solo developer or in small teams.

– **Complexity**: Managing separate front-end and back-end stacks required extensive effort, from business analysis to deployment.
– **Resource Constraints**: As a freelancer for the Czech Academy of Sciences, Ondrej often worked alone on administrative applications, where hiring additional help was impractical due to bureaucratic limitations.
– **Time-Consuming Processes**: Older frameworks like GWT, which initially simplified his workflow, became obsolete and introduced slow build times (up to 5 hours for transpilation).

![Картинка 3.png]({{strapiUrl}}/uploads/Kartinka_3_56322d9093.png)

These challenges led Ondrej to seek a more efficient solution — one that would allow him to focus on business logic rather than juggling multiple technologies.

Discovering Jmix: A Turning Point

Ondrej was actively looking for a framework that would let him build full-stack applications using only Java. When he discovered Jmix, its modern approach and developer-centric features immediately caught his attention — it looked like the tool he’d been searching for.

Key Benefits He Experienced:

1. **Unified Development**: Jmix’s back-end-driven approach eliminated the need to worry about front-end security and state management, as the client side is inherently trusted.
2. **Rapid Prototyping**: Using Jmix’s Figma component library, Ondrej could quickly create mock-ups and iterate with stakeholders before diving into development.
3. **Speed of Development**: Building CRUD views and configurable applications became significantly faster, allowing him to deliver projects in weeks rather than months.

![Картинка 4.png]({{strapiUrl}}/uploads/Kartinka_4_71b6827400.png)

Real-World Applications: Success Stories

Ondrej has implemented several critical projects with Jmix, including:

1. Czech Academy of Sciences – Economic Department

a. A grant management system for 50+ institutions, handling requests, approvals, and PDF generation.
b. Supports 300 – 400 users with no performance issues, leveraging add-ons like Reporting and OpenID.

2. Scientific Evaluation System

a. A large-scale application for evaluating thousands of scientific articles by international experts.
b. Designed for 3,000 – 5,000 users, currently stress-tested with 1,000 active users ahead of its April launch.

For smaller projects, Ondrej notes that a 15 – 20 screen application can be built in just two weeks — a testament to Jmix’s efficiency.

![Картинка 2.png]({{strapiUrl}}/uploads/Kartinka_2_4b3217a1e4.png)

Recommendations for Using Jmix

Based on his experience, Ondrej recommends Jmix for:

– Freelancers and solo developers looking for an efficient and powerful development framework.
– Large organizations needing rapid prototyping to validate business concepts quickly.
– Internal business applications across industries, including banking, research, and corporate sectors.

Jmix’s flexibility and ease of development make it a strong choice for a wide range of projects with a predictable number of users.

![Картинка 6.png]({{strapiUrl}}/uploads/Kartinka_6_e497521d66.png)

The Future with Jmix

Ondrej plans to continue using Jmix for upcoming projects, particularly for internal company systems. His goal is to avoid the “front-end fatigue” of frameworks like React and Angular, focusing instead on solving business problems efficiently.

His Advice to Other Developers:

“If you want to concentrate on business logic and avoid hunting pixels or debugging race conditions, Jmix is the way to go. It’s a powerful tool for freelancers, prototyping, and large enterprises looking for manageable solutions.”

Source: One Framework, One Developer, Full Power: Ondrej’s Jmix Experience

This article explores why upgrading to Jmix 2 is a strategic move for your development projects.If you’re still using Jmix 1, now is the perfect time to migrate to Jmix 2. Built on a modern, actively supported technology stack and packed with powerful new features, Jmix 2 offers significant advantages over its predecessor. This article explores why upgrading to Jmix 2 is a strategic move for your development projects, enhancing productivity, security, and user experience while future-proofing your applications.

## Modern Technology Stack for Enhanced Security and Performance

Jmix 2 is built on a cutting-edge technology stack, including Spring Boot 3 and Vaadin 24, which are updated with each Jmix feature release every four months. In contrast, Jmix 1 is tied to Spring Boot 2 and Vaadin 8, both of which are no longer officially supported. This means Jmix 1 is limited to critical bug fixes and select security patches, with some third-party dependency vulnerabilities unfixable due to incompatibility with newer versions.

With Jmix 2, regular dependency updates ensure your applications benefit from the latest security patches, reducing vulnerabilities and enhancing safety. Additionally, newer Java versions in Jmix 2 deliver improved performance and modern language features, enabling developers to write cleaner, more efficient code. This forward-looking approach ensures your applications remain secure, performant, and aligned with industry standards.

## Mobile-Friendly and Customizable UI with Vaadin 24

Jmix 2 leverages Vaadin 24 to deliver a mobile-friendly user interface out of the box. Unlike Jmix 1, which requires separate mobile applications or complex workarounds, Jmix 2 supports responsive layouts, allowing you to optimize your UI for mobile devices without additional development effort. This streamlines development and ensures a consistent user experience across desktops, tablets, and smartphones.

Moreover, Vaadin 24 provides greater control over your application’s look and feel. With direct access to DOM elements and straightforward CSS styling, customizing the UI is simpler than ever. Jmix 2 also includes Java wrappers for standard HTML elements like `div`, `span`, `p` and `hr`, making it easier to create tailored, visually appealing interfaces that align with your brand. Additionally, the frontend part of Jmix 2 is now based on the web components standard, significantly simplifying the integration of third-party JavaScript components and libraries, enabling developers to enhance their applications with a wider range of modern tools and functionalities.

## Enhanced Navigation and User Experience

Jmix 2 introduces standard browser navigation for opening views, aligning with familiar web browsing behaviors. Users can now open views in new browser tabs via the context menu and use deep links to access specific application views directly. For those who prefer the Jmix 1 approach of opening screens in internal tabs within a single browser tab, Jmix 2 offers the optional **Tabbed Application Mode** add-on, providing flexibility to suit different preferences.

## New Features and Improvements in Jmix 2

Jmix 2 introduces a range of powerful add-ons and functionalities that are absent in Jmix 1, empowering developers to build more sophisticated applications with less effort:

– **Kanban Add-on**: visualizes project workflows with a Kanban board component, using cards for tasks and columns for project stages.
– **Superset Add-on**: allows you to embed Apache Superset dashboards into your Jmix application views, enhancing data visualization capabilities.
– **UI Constraints Add-on**: manages UI component visibility and accessibility using declarative policies in resource roles, even for components not tied to the data model.
– **OpenID Connect Add-on**: simplifies external authentication with providers like Keycloak, mapping user attributes and roles to Jmix users seamlessly.
– **REST DataStore Add-on**: allows you to easily integrate external Jmix applications, accessing remote entities through the `DataManager` interface as if they were local, with full CRUD functionality.
– **Authorization Server Add-on**: provides authentication for REST APIs in compliance with OAuth 2.1, ensuring secure and standardized API access.
– **OpenAPI Integration in Studio**: configures OpenAPI client generators and automatically generates DTO entities, mappers, and services for integration with external REST APIs.
– **Data Repositories**: built on Spring Data, Jmix 2’s data repositories combine the simplicity of repository interfaces with advanced Jmix data access features like data access control, entity events and cross-datastore references.
– **Entity Comments**: lets you add comments to data model entities and attributes, improving documentation and collaboration.

Jmix 2 brings notable enhancements to existing features, streamlining development and improving usability:

– **Studio UI Preview**: unlike Jmix 1’s schematic previews, Jmix 2’s Studio shows views with real components and styles, closely mirroring the running application.
– **Hot Deployment Status**: a new icon in Studio indicates the hot deployment status of view controllers, descriptors, message bundles, and roles, keeping developers informed about the delivery of the latest changes in the source code to the working application.
– **UUIDv7 for Entity Identifiers**: Jmix 2 uses UUIDv7 for entity identifiers, significantly boosting database operation performance compared to Jmix 1.

## Closing the Gap: Grouping DataGrid Coming Soon

The only notable feature missing in Jmix 2 compared to Jmix 1 is the GroupTable. However, this will be addressed with the upcoming Grouping DataGrid, set for release in October 2025. Once implemented, Jmix 2 will surpass Jmix 1 in every aspect, making it the definitive choice for modern application development.

## Jmix AI Assistant and Growing Ecosystem

**Jmix AI assistant** is optimized for Jmix 2 development, offering superior guidance compared to Jmix 1. Additionally, Jmix 2 benefits from a rapidly expanding ecosystem of documentation, guides, learning courses, and code examples. Unlike Jmix 1, which is in maintenance mode with only critical updates, Jmix 2’s resources are continuously improved, providing developers with more comprehensive support. This growing knowledge base also enhances compatibility with third-party AI assistants, making Jmix 2 projects easier to develop and maintain.

## Future-Proof Your Development with Jmix 2

Jmix 2 is a dynamic, evolving platform that receives new features and improvements every four months, ensuring your applications stay current with the latest technologies. In contrast, Jmix 1 is in maintenance mode, receiving only critical fixes. By migrating to Jmix 2, you gain access to a modern, secure, and feature-rich framework that enhances developer productivity and delivers superior user experiences.
Source: Upgrade to Jmix 2: Future-Proof Your Projects

What if you need to embed features from a Jmix, Vaadin, or Spring application into another website or web application?What if you need to embed features from a Jmix, Vaadin, or Spring application into another website or web application? If your target platform isn’t a portal system, the common approach is to use IFrame technology for this purpose.

However, setting up IFrames today may not be entirely straightforward.

When deploying outside your local PC, the application opened in an IFrame will likely require browser cookie support to function properly. Modern security standards dictate that cross-site cookie exchange only works when the following requirements are met:

– Both the target site and the embedded application use a trusted HTTPS setup.
– Session cookies have the Secure property enabled.
– The SameSite property is disabled for these cookies.

This means extra server configuration is required, even for testing or staging environments.

As an example, we’ll use a server with the IP address 10.5.44.78, hosting both a Docker-based Jmix application and a static website that will be served with nginx frontend server configured for HTTPS. This could be run by a virtual server or a local virtual machine running a Linux-based OS.

For production, you can purchase SSL certificates or use free options like Let’s Encrypt/ACME software. For testing purposes, we’ll set up fake domain names and map them to the server’s IP in the /etc/hosts file (located in Windows\System32\drivers\etc on a Windows PC). Add the following line to this file:

“`10.5.44.78 app.jmix site.jmix “`

After that, when you open “`https://app.jmix in browser“`, it will send requests to IP-address we specified above.

For easier access, you can also install a public SSH key (which you may need to generate first) on the remote server using the following command:

“`ssh-copy-id [email protected]“`

## The website

For this simple website, we won’t use any libraries or frameworks. Instead, we’ll write code that opens a browser-native dialog window when a link is clicked, embedding the IFrame contents.

Place the following code inside a “`

My Agile Privacy

This site uses technical and profiling cookies. 

You can accept, reject, or customize the cookies by clicking the desired buttons. 

By closing this notice, you will continue without accepting. 


This site complies with the Data Protection Act (LPD), Swiss Federal Law of September 25, 2020, and the GDPR, EU Regulation 2016/679, regarding the protection of personal data and the free movement of such data.