SupportWriter space ↗
← Back to the journal
Vaadin

Getting started with Vaadin Flow: building web UIs in pure Java

Learn what Vaadin Flow is, create a Spring Boot project, and build your first interactive web view in pure Java without writing HTML or JavaScript.

DPutu Adi Guna Permana · 08 Oct 2026 · 6 min read

What is Vaadin?

Vaadin is an open source framework for building web applications in Java. Its server-side flavor, Vaadin Flow, lets you build the entire user interface in Java: you create components such as text fields, buttons, grids, and dialogs as Java objects, wire them together with listeners, and Vaadin renders them in the browser as modern web components.

There is no REST API to design between frontend and backend, no JSON mapping, and no separate JavaScript build to maintain. The UI code runs on the server, right next to your services and repositories, so calling business logic is just a method call.

This makes Vaadin a strong fit for:

  • Internal business applications, admin panels, and back-office tools.
  • Data-heavy UIs with forms, tables, and dashboards.
  • Java teams who want to ship full-stack features without switching languages.

This series uses Vaadin Flow with Spring Boot. The examples target Vaadin 24 or later, which requires Java 17 or newer; newer major versions may raise the baseline, so check the release notes for your version.

How Vaadin Flow works

When a user opens a page, Vaadin creates a UI instance on the server for that browser tab and builds the component tree you defined. The browser receives a lightweight client engine that renders the components. When the user clicks a button, the browser sends the event to the server, your Java listener runs, and Vaadin sends back only the changes to the UI.

Two consequences are worth remembering:

  1. State lives on the server. Each user session holds its UI state in memory, which keeps code simple but means memory usage grows with active users.
  2. It is secure by default. Business logic never runs in the browser, so users cannot tamper with it by editing JavaScript.

Creating a project

The quickest start is the project generator at start.vaadin.com, or Spring Initializr with the Vaadin dependency. Both give you a Maven or Gradle project with the Maven wrapper included.

Run it with:

./mvnw

or start the Application class from your IDE. The first start downloads dependencies and may take a while. Afterwards, open http://localhost:8080.

The entry point is a regular Spring Boot application:

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

Your first view

A view is a component class annotated with @Route. Here is a small greeting view:

import com.vaadin.flow.component.Key;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant;
import com.vaadin.flow.component.html.H1;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;

@Route("")
@PageTitle("Hello Vaadin")
public class HelloView extends VerticalLayout {

    public HelloView(GreetingService greetingService) {
        var name = new TextField("Your name");
        name.setPlaceholder("e.g. Putu");

        var greet = new Button("Say hello", event -> {
            String message = greetingService.greet(name.getValue());
            Notification.show(message);
        });
        greet.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
        greet.addClickShortcut(Key.ENTER);

        add(new H1("Welcome to Vaadin"), name, greet);
    }
}

And the service it uses:

@Service
public class GreetingService {

    public String greet(String name) {
        if (name == null || name.isBlank()) {
            return "Hello, stranger!";
        }
        return "Hello, " + name.strip() + "!";
    }
}

Things to notice:

  • @Route("") maps the view to the root URL. @Route("hello") would map it to /hello.
  • Views are Spring beans, so services are injected through the constructor like anywhere else in Spring.
  • VerticalLayout stacks its children vertically. Calling add(...) puts components on the page.
  • The button's click listener is a plain Java lambda that runs on the server.
  • addClickShortcut(Key.ENTER) lets users press Enter instead of clicking.

Save the file and the browser reloads automatically in development mode.

The component library

Vaadin ships with a large set of ready-made components, all with a consistent look:

Category Examples
Input TextField, PasswordField, EmailField, IntegerField, DatePicker, ComboBox, Checkbox
Layout VerticalLayout, HorizontalLayout, FormLayout, SplitLayout, AppLayout
Data Grid, TreeGrid, VirtualList
Feedback Notification, Dialog, ConfirmDialog, ProgressBar
Navigation SideNav, Tabs, MenuBar, RouterLink

All components work with keyboard navigation and screen readers out of the box, which saves a lot of accessibility work.

Styling with the Lumo theme

The default theme, Lumo, already looks clean and professional. Adjust it with variants:

greet.addThemeVariants(ButtonVariant.LUMO_PRIMARY, ButtonVariant.LUMO_LARGE);

For spacing and layout tweaks, the LumoUtility class provides utility CSS class names:

layout.addClassNames(LumoUtility.Padding.LARGE, LumoUtility.Gap.MEDIUM);

For anything more, put regular CSS in your application's theme folder (for example src/main/frontend/themes/my-theme/styles.css) and activate the theme on your AppShellConfigurator class with @Theme("my-theme").

Building for production

Development mode is optimized for fast feedback. For deployment, create an optimized build:

./mvnw clean package -Pproduction

The result is a regular executable Spring Boot JAR with the frontend bundle already compiled and minified. Run it with java -jar target/my-app.jar, or package it into a container image.

When Vaadin is not the best fit

Every tool has trade-offs. Vaadin Flow is less suitable for public, content-heavy websites that need SEO and must handle huge numbers of anonymous visitors, because each session keeps state on the server. For those cases, server-rendered HTML or a static site is usually a better match. For business applications used by employees or registered customers, Vaadin's productivity is hard to beat.

Exercise

Extend HelloView with a ComboBox<String> for choosing a greeting language (English, Indonesian, Spanish). Pass the selected language to GreetingService, and disable the button while the name field is empty using a value change listener.

← Explore more notes