Building for production
So far we ran the application in development mode: Vaadin watched for changes, showed detailed errors and a developer panel in the corner of the page. On a server none of this is needed, it is even harmful. Production mode is a ready build of the interface without developer tools and with short error messages. Spring Boot packs the whole application together with the Tomcat server into one JAR file.
Building
./mvnw clean packageMaven compiles the code, runs the tests, and the vaadin-maven-plugin prepares the frontend. The log shows:
[INFO] Tests run: 7, Failures: 0, Errors: 0, Skipped: 0
[INFO] --- vaadin:25.3.0:build-frontend (default) @ blog ---
[INFO] Checking if a production mode bundle build is needed
[INFO] A production mode bundle build is not needed
[INFO] Building jar: .../blog/target/blog-1.0-SNAPSHOT.jar
[INFO] BUILD SUCCESSThe lines are shortened. "Bundle build is not needed" means Vaadin took a ready-made build of the standard components, and Node.js was not needed. If you add your own web components or add-ons with frontend code, the plugin builds the frontend itself and downloads Node.js when needed.
Development mode stays out of the build
The vaadin-dev dependency in pom.xml is marked <optional>true</optional>. Spring Boot does not put such dependencies into the final JAR, and without it Vaadin switches to production mode by itself. Vaadin 25 needs no separate Maven profile for this.
Running
java -jar target/blog-1.0-SNAPSHOT.jar... DefaultDeploymentConfiguration : Vaadin is running in production mode.
... TomcatWebServer : Tomcat started on port 8080 (http) with context path '/'
... Application : Started Application in 17.777 secondsOpen http://localhost:8080 — the same admin panel, but without the developer panel. The JAR is about 75 MB: it contains Spring, Tomcat, Hibernate and all Vaadin components. The server needs only Java 21 or newer.
Server settings
Values from application.properties can be overridden at startup without rebuilding the JAR:
java -jar target/blog-1.0-SNAPSHOT.jar --server.port=9000| What | How to set it |
|---|---|
| Port | --server.port=9000 or the PORT variable if the settings say server.port=${PORT:8080} |
| Database | SPRING_DATASOURCE_URL, SPRING_DATASOURCE_USERNAME, SPRING_DATASOURCE_PASSWORD |
| Settings profile | --spring.profiles.active=prod and an application-prod.properties file |
For real work replace H2 with PostgreSQL: in-memory H2 data disappears on restart. Pass passwords as environment variables instead of keeping them in application.properties in Git.
Behind a proxy
Usually nginx with HTTPS stands in front of the application. Vaadin uses WebSocket (push), so the proxy must pass the Upgrade and Connection headers. With several servers, turn on sticky sessions: view state lives in the memory of the server where the user logged in.
Common mistake
The JAR is started with an old Java:
java.lang.UnsupportedClassVersionError: com/example/blog/Application has been compiled by a more recent version of the Java Runtime (class file version 69.0), this version of the Java Runtime only recognizes class file versions up to 61.0Version 69 is Java 25, 61 is Java 17. Install the same Java version as <java.version> in pom.xml, or newer, on the server.