Differences Between Vaadin platform and V8 Applications

The UI Class is Different and it is Optional

A subcass of UI is not needed in Vaadin Flow applications. It is still there, but it is not the starting point of the application anymore, and you don’t need to define your custom UI. Adding the content to show is handled by Router which is introduced in the next chapter.

Most things you have previously done in the UI class, can be achieved in alternative, better ways. These alternatives are covered in this documentation, but if some information is missing, please create an issue so we may add the necessary information.

In Vaadin 8 and 7, the UI referenced a <div> element which was a child of the <body> in the DOM. In Vaadin platform, the UI is instead directly connected to to the <body> element.

The API in the UI class in Vaadin Flow has gone through a clean-up and some API that is not meant for application developers to access has been moved to internal classes. For using API that is still in UI, the same UI.getCurrent() call can still be used to obtain a reference to the UI for the currently active request.

While migrating, you still might want to create your own UI, and you can see an example for that in the next topic.

No @PreserveOnRefresh

There is currently no support for the @PreserveOnRefresh functionality in Vaadin Flow. Each browser refresh will reload the UI. At the same time, reloading the UI is a smaller problem than before since the user’s location will typically be preserved in the URL.

The Servlet Definition is Optional

Similarly as the UI, the servlet definition is optional in Vaadin Flow. And the reason is also the same, the new Routing API, which is introduced in the next chapter. By default the servlet is automatically mapped to the root context path. You can of course still configure the servlet yourself, and it happens the same way as previously:

@WebServlet(urlPatterns = "/*", name = "myservlet", asyncSupported = true,
// Example on initialization parameter configuration
initParams = {
        @WebInitParam(name = "frontend.url.es6", value = "http://mydomain.com/es6/"),
        @WebInitParam(name = "frontend.url.es5", value = "http://mydomain.com/es5/") })
// The UI configuration is optional
@VaadinServletConfiguration(ui = MyUI.class, productionMode = false)
public class MyServlet extends VaadinServlet {

// this is not necessary anymore, but might help you get started with migration
public class MyUI extends UI {
    protected void init(VaadinRequest request) {
        // do initial steps here.
        // previously routing

Single Step Bootstrap and No UIProvider

In Vaadin 8, the application bootstrap happened in two phases. The initial page response only contained code to obtain more data related to the browser, data which was not available in the initial request. Based on this, the correct UI would be created. This was a good option back then since mobile devices capabilities required completely own client engine and UI to deliver the best possible end user experience.

This is not necessary anymore, and in Vaadin Flow the UI content is delivered on the first response and the application is bootstrapped without further network activity. This means that UIProvider has become obsolete.

Modifying the Bootstrap Page

If you had previously customized the initial response with BootstrapListener, this tutorial show the new and simpler way of customizing the initial page response using PageConfigurator or specific annotations on the application’s main layout.

BoostrapListener is still there and can be registered using a VaadinServiceInitListener, as shown by this tutorial.

Configuring Server Push

As a custom UI class is no longer needed, you can configure the used PushMode for your app in the main layout of your application. Please see the Server Push Configuration tutorial for more info.

Loading Indicator Configuration

The default loading indicator is the same as in Vaadin 8 Valo Theme. If you want to customize it or disable it, you should see the loading indicator documentation.

Similarities and Package Naming

Some of the Java code in Vaadin Flow is directly inherited from Vaadin 8. Even in these cases, the package names are however changed. This is because we want to make it possible to use V8 components and views without classpath conflicts inside Vaadin Flow using the multiplatform tool. Thus the package names for Vaadin platform contain flow that separates them from the V8 packages.

Are you planning on migrating your application? Get help from Vaadin experts.

Open in a
new tab
export class RenderBanner extends HTMLElement {
  connectedCallback() {

  renderBanner() {
    let bannerWrapper = document.getElementById('tocBanner');

    if (bannerWrapper) {

    let tocEl = document.getElementById('toc');

    // Add an empty ToC div in case page doesn't have one.
    if (!tocEl) {
      const pageTitle = document.querySelector(
        'main > article > header[class^=PageHeader-module--pageHeader]'
      tocEl = document.createElement('div');

      pageTitle?.insertAdjacentElement('afterend', tocEl);

    // Prepare banner container
    bannerWrapper = document.createElement('div');
    bannerWrapper.id = 'tocBanner';

    // Banner elements
    const text = document.querySelector('.toc-banner-source-text')?.innerHTML;
    const link = document.querySelector('.toc-banner-source-link')?.textContent;

    const bannerHtml = `<div class='toc-banner'>
          <a href='${link}'>
            <div class="toc-banner--img"></div>
            <div class='toc-banner--content'>${text}</div>

    bannerWrapper.innerHTML = bannerHtml;

    // Add banner image
    const imgSource = document.querySelector('.toc-banner-source .image');
    const imgTarget = bannerWrapper.querySelector('.toc-banner--img');

    if (imgSource && imgTarget) {