Docs

Documentation versions (currently viewingVaadin 24)

Upgrading from Vaadin 23

Changes needed to upgrade an application from Vaadin 23 to the latest version.

This guide goes through the changes you’ll need to make in your applications when upgrading from Vaadin 23 to the latest version. After making them, your application should compile, run, behave, and look the way it did before you upgraded.

Tip
Upgrading from Earlier Version
See Vaadin 14 to 23 Upgrade Instructions if you’re upgrading from a version earlier than Vaadin 23.

Many of the breaking changes are needed because of fundamental changes in the Java platform and the major dependencies on which Vaadin relies. This includes the following:

Servlet 6

Vaadin 24 is based on Servlet 6 specifications. It’s compatible with Jakarta EE 10. Vaadin encapsulates the usage of the classes from javax and jakarta packages. Therefore, application code doesn’t need to use servlets, directly. Nevertheless, this is still needed in various cases — like accessing cookies, setting servlet parameters, etc.

Spring Boot 3

Vaadin 24 uses the latest Spring Boot 3 and Spring Framework 6 versions. This leads to making breaking changes in Spring-based features, compared to earlier Spring Boot 2 and Spring Framework 5 versions.

Java 17

Vaadin 24 requires Java 17 or later. This is dictated by Spring Framework and newer versions of application servers.

Overview

Vaadin 24 doesn’t change fundamentally how applications are developed and behave. Nevertheless, the upgrade process requires the following essential tasks and tests:

Preparation

Upgrade the Vaadin version in the project’s pom.xml file, checking for the latest Vaadin 24 release in GitHub.

Jakarta EE 10

Convert package names to Jakarta EE 10 namespace.

Upgrade Spring

For Spring-based applications, upgrade to Spring Boot 3 or Spring Framework 6, depending on which is used in your project. For non-Spring applications, upgrade the application server version to one that’s compatible with Jakarta EE 10.

Other Dependencies

Upgrade third-party dependencies used in your project (e.g., Maven/Gradle plugins, libraries, frameworks) to the Jakarta and Spring-compatible versions.

Verify & Test

Ensure your application is not using deprecated code fragments.

Make sure your application runs well on Java 17 runtime.

Verify that the frontend build works as it should with Vite since webpack is no longer supported.

Limitations

Portlet and OSGi integrations are not included for two reasons: First, the latest Portlet 3 specification corresponds to Servlet 3, and it doesn’t work with Servlet 6. Second, a Jakarta EE 10 compatible version of OSGi core runtime Apache Felix 8 is under development. The Apache Karaf container is based on Apache Felix and doesn’t have a Jakarta-compatible version.

Preparation

Upgrade the Vaadin version in the pom.xml and gradle.properties files to the latest release like so:

<vaadin.version>24.6.2</vaadin.version>

See the list of releases on GitHub for the latest one.

Jakarta EE 10 Namespaces

You can use the free tools, Eclipse Transformer and Apache migration tool for the package name conversion.

When applied to a project, they’ll convert Java class imports, manifests, property files, and other resources to use jakarta.* namespace when needed. Conversion instructions are in each tool’s README file.

The last versions of IntelliJ IDEA offer migration refactoring tools, including a Java EE to Jakarta EE package converter. Make sure that the Jakarta specifications in your project have the correct versions. Refer to the full list of Jakarta EE 10 specifications for more information.

Below are a few examples:

<dependency>
    <groupId>jakarta.servlet</groupId>
    <artifactId>jakarta.servlet-api</artifactId>
    <version>6.0.0</version>
</dependency>
<dependency>
    <groupId>jakarta.annotation</groupId>
    <artifactId>jakarta.annotation-api</artifactId>
    <version>2.1.0</version>
</dependency>
<dependency>
    <groupId>jakarta.enterprise</groupId>
    <artifactId>jakarta.enterprise.cdi-api</artifactId>
    <version>4.0.0</version>
</dependency>
<dependency>
    <groupId>jakarta.enterprise.concurrent</groupId>
    <artifactId>jakarta.enterprise.concurrent-api</artifactId>
    <version>3.0.0</version>
</dependency>

Spring Upgrade Instructions

Spring Boot 3 and Spring Framework 6 don’t fundamentally change how applications are developed. The main changes are regarding Jakarta EE 10 namespaces and supported products, the Java version, and the dependency upgrades and deprecations.

Spring Boot 3 and Framework 6 use new versions of third-party dependencies: Hibernate 6, Hibernate Validator 8, servlet containers (e.g., Jetty 11, Tomcat 10.1), and many others. Spring has available the Dedicated Migration Guide for Spring-boot 3.0 and the Upgrading to Spring Framework 6.x Guide. You may want to consult them.

To browse a full list of changes, see the Spring-boot 3.0 Release Notes and the What’s New in Spring Framework 6.x page.

The following sections provide a general overview of the changes needed for Spring-based Vaadin applications.

Upgrade Spring to Latest

You’ll need to upgrade Spring to the latest versions, including the starter parent dependency:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>3.0.0</version>
</parent>

Deprecation

The deprecated VaadinWebSecurityConfigurerAdapter class was removed since Spring no longer includes the WebSecurityConfigurerAdapter class. Use instead the VaadinWebSecurity base class for your security configuration. Below is an example of this:

@EnableWebSecurity
@Configuration
public class SecurityConfig extends VaadinWebSecurity {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        /**
         * Delegating the responsibility of general configuration
         * of HTTP security to the superclass.
         *
         * It's configuring the following:
         * - Vaadin's CSRF protection by ignoring internal framework requests,
         * - default request cache,
         * - ignoring public views annotated with @AnonymousAllowed,
         * - restricting access to other views/endpoints, and
         * - enabling ViewAccessChecker authorization.
         */

        // You can add any possible extra configurations of your own
        // here - the following is just an example:
        http.rememberMe().alwaysRemember(false);

        // Configure your static resources with public access before calling
        // super.configure(HttpSecurity) as it adds final anyRequest matcher
        http.authorizeHttpRequests(auth -> {
            auth.requestMatchers(new AntPathRequestMatcher("/admin-only/**"))
                    .hasAnyRole("admin")
            .requestMatchers(new AntPathRequestMatcher("/public/**"))
                    .permitAll();
        });
        super.configure(http);

        // This is important to register your login view to the
        // view access checker mechanism:
        setLoginView(http, LoginView.class);
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        // Customize your WebSecurity configuration.
        super.configure(web);
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * Demo UserDetailsManager which only provides two hardcoded
     * in-memory users and their roles.
     * This shouldn't be used in real-world applications.
     */
    @Bean
    public UserDetailsService userDetailsService(
            PasswordEncoder passwordEncoder) {
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(User.withUsername("user")
                .password(passwordEncoder.encode("userPass"))
                .roles("USER").build());
        manager.createUser(User.withUsername("admin")
                .password(passwordEncoder.encode("adminPass"))
                .roles("USER", "ADMIN").build());
        return manager;
    }
}

In the example here, AuthenticationManagerBuilder — used in Spring Boot 2 — is replaced by UserDetailsService. Also, http.authorizeRequests().antMatchers() is replaced with http.authorizeHttpRequests(auth → auth.requestMatchers()).

Spring Security

If the application is using Spring Security 5, the default behavior is for the SecurityContext to be saved automatically to the SecurityContextRepository using the SecurityContextPersistenceFilter.

In Spring Security 6, users now must explicitly save the SecurityContext to the SecurityContextRepository.

You can return the old behavior by adding to configuration(HttpSecurity) the line http.securityContextsecurityContext) → securityContext.requireExplicitSave(false;.

For more information see Servlet Migrations - Session Management.

Java Version

Java 17 or later is required. Below is an example of how to use this version:

<properties>
    <java.version>17</java.version>
    <!-- OR: -->
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
</properties>

Application Servers

Before migrating, find the corresponding version of the Jakarta EE 10-compatible application server used in your project. See Jakarta Compatible Products for more information.

CDI 4.0 specification — which is part of Jakarta EE 10 — changes the default value of the bean-discovery-mode attribute to annotated and uses annotated as the default when an empty beans.xml file is found in a deployment. See Jakarta CDI page for more information.

To let the container scan and manage Vaadin components and views when the bean-discovery-mode attribute is not defined and the default is used, you should annotate Vaadin components and views with the com.vaadin.cdi.annotation.CdiComponent to allow them to be detected correctly as CDI beans.

As an alternative, you can set bean-discovery-mode=all in the beans.xml file if it’s applicable to your project. However, this isn’t recommended.

Frontend Sources Directory

Vaadin uses the {project directory}/src/main/frontend/ directory as the default location for frontend sources. The legacy location {project directory}/frontend/ is still supported and used if the {project directory}/src/main/frontend/ directory doesn’t exist.

Although it’s currently optional, if you’re using the legacy location, you should move your files to a new location, as support for this may be removed in the future releases.

Unification with Hilla & Integration with React

Vaadin 24.4 and later versions unify the server and client development approaches known as Vaadin Flow and Hilla, respectively. This makes it easier to create hybrid applications, including:

  • unify dependencies for the Vaadin, making the project configuration simpler;

  • develop React-based routes and components in Vaadin Flow applications;

  • export Flow components or entire views into frontend views implemented with React; and

  • use unified routing based on React Router.

Hilla & React Dependencies

Vaadin 24 includes React dependencies, such as React, React Router, and Vaadin React-based components provided by Vaadin. These dependencies allow you to start developing immediately with React.

Vaadin React includes free, core components and commercial (i.e., professional) components. These components are shipped in the separate npm packages: @vaadin/react-components, which is only free; and @vaadin/react-components-pro, which is only commercial. Vaadin adds both of these packages to package.json if the com.vaadin:vaadin artifact is in the project’s configuration:

<dependency>
	<groupId>com.vaadin</groupId>
	<artifactId>vaadin</artifactId>
</dependency>

It adds only @vaadin/react-components if com.vaadin:vaadin-core is used:

<dependency>
	<groupId>com.vaadin</groupId>
	<artifactId>vaadin-core</artifactId>
</dependency>

Vaadin Flow applications don’t need any changes regarding React or Hilla dependencies management. However, the opt-out options are available for the following cases:

  • Lit is used for frontend development instead of React;

  • having Hilla or React dependencies is undesirable; and

  • you need the legacy vaadin-router (e.g. if your project uses an add-on that needs it).

Opting-Out of React

To opt-out, change both reactEnable plugin configuration parameter and vaadin.react.enable configuration property to false.

Maven plugin configuration parameter in the vaadin-maven-plugin:

<plugin>
   <groupId>com.vaadin</groupId>
   <artifactId>vaadin-maven-plugin</artifactId>
   <configuration>
       <reactEnable>false</reactEnable>
   </configuration>
</plugin>

Below is the configuration property with Spring Boot application properties:

vaadin.react.enable=false

Disabling it excludes React completely from your project and fallbacks to vaadin-router and Lit.

Two Places for Same Property

Two properties exists mainly to support the development and production modes. reactEnable is effective for both; vaadin.react.enable, though, is effective only for development.

Production package and bundle is built by running the Vaadin Maven and Gradle plugin with build-frontend goal. The reactEnable plugin configuration parameter value is contained in the build information file inside the package, which is used as a default value in runtime.

Configuration property vaadin.react.enable overrides the default value in the production package at runtime. However, it doesn’t change the production bundle content.

Running an application with the vaadin.react.enable in production mode means possibly using a different value than what was used when the production package was built. Both properties should have the same value to avoid confusion as to which is effective.

Opting-Out of React with Spring

System property has priority over application property. When running a Spring application with Maven, you may need to wrap system property in -Dspring-boot.run.jvmArguments=vaadin.react.enable=false".

Simplified Maintenance

To make it easier to keep both properties the same, Spring supports Automatic Property Expansion with Maven and with Gradle. Please follow the instructions in the Spring documentation to enable this feature.

When running with Maven and using spring-boot-starter-parent, property value can have @reactEnable@, which is replaced with the value of the reactEnable Maven project property. Otherwise, please follow the Spring documentation to see how to enable resources filtering and set maven-resources-plugin configurations.

vaadin.react.enable=@reactEnable@
<properties>
    <reactEnable>false</reactEnable>
</properties>
<plugin>
   <groupId>com.vaadin</groupId>
   <artifactId>vaadin-maven-plugin</artifactId>
   <configuration>
       <reactEnable>${reactEnable}</reactEnable>
   </configuration>
</plugin>
Opting-Out of React without Spring

When Spring is not used, set vaadin.react.enable system property or react.enable initialization parameter.

Opting-Out of React Components

If you don’t need Vaadin’s React components, you can opt-out by excluding the flow-react package in your dependencies. This replaces the @vaadin/react-components and @vaadin/react-components-pro packages in your package.json with @vaadin/* web components:

<dependency>
	<groupId>com.vaadin</groupId>
	<artifactId>vaadin</artifactId>
	<exclusions>
		<exclusion>
			<groupId>com.vaadin</groupId>
			<artifactId>flow-react</artifactId>
		</exclusion>
	</exclusions>
</dependency>

This example exclude Hilla from a project when using Maven:

<dependency>
	<groupId>com.vaadin</groupId>
	<artifactId>vaadin</artifactId>
	<exclusions>
		<exclusion>
			<groupId>com.vaadin</groupId>
			<artifactId>hilla</artifactId>
		</exclusion>
		<exclusion>
			<groupId>com.vaadin</groupId>
			<artifactId>hilla-dev</artifactId>
		</exclusion>
	</exclusions>
</dependency>

This example is for when you’re using Gradle:

buildscript {
    configurations.classpath {
        exclude group: 'com.vaadin', module: 'hilla-engine-core'
    }
}

dependencies {
    implementation ("com.vaadin:vaadin") {
        exclude group: 'com.vaadin', module: 'hilla-dev'
    }
}
hilla.active=false

The following Hilla dependencies are included in Vaadin. You don’t need to include these explicitly:

  • dev.hilla:hilla-bom

  • dev.hilla:hilla-react

  • dev.hilla:hilla

Frontend Bundles & Hot Deploy Modes

Vaadin chooses using a pre-compiled frontend bundle, or re-building a new bundle, or starting a frontend development server. If it detects Hilla views in a project, it uses development server — unless you set the configuration parameter, vaadin.frontend.hotdeploy=false. Conversely, for Flow applications it uses frontend bundle — unless you set the configuration parameter, vaadin.frontend.hotdeploy=true.

Default Location for Client-Side Views

Place your React client-side views in the src/main/frontend/views/ directory. Vaadin searches for any .tsx or .jsx React views. It registers them as React routes if they’re present in this directory or subdirectories. See Routing for more details about File-Based Routing.

Polymer Templates

Polymer support has been deprecated since Vaadin 18 was released in November 2020, in favor of faster and simpler Lit templates. The built-in support for Polymer templates has been removed and is only available for Prime and Ultimate customers via an addon. However, a free conversion tool is also available to assist you in converting your Polymer templates to Lit.

Commercial Polymer Template Addon

If you have a Prime or Ultimate subscription, you can continue to use Polymer templates by adding the following dependency to your pom.xml file:

<dependency>
    <groupId>com.vaadin</groupId>
    <artifactId>flow-polymer-template</artifactId>
</dependency>

Then you’ll need to update all imports of the PolymerTemplate classes to the new coordinates: com.vaadin.flow.component.polymertemplate.PolymerTemplate.

Polymer to Lit Conversion Tool

You can use the free conversion tool to facilitate the migration from Polymer to Lit by converting automatically basic Polymer constructions into their Lit equivalents in Java and JavaScript source files.

Limitations

The converter covers only basic cases. More advanced cases, such as TypeScript source files or usage of internal Polymer API, should still be converted manually.

See the Polymer-to-Lit converter documentation for more information about limitations and supported transformations.

Usage

Regarding usage, run the converter in your project’s root folder as follows: