Using Vaadin Flow’s Server‑Side Navigation for Clean URL‑Driven Views
Learn how Vaadin Flow’s server‑side navigation maps Java views to URLs, enables programmatic moves, and handles typed route parameters—plus tips on managing view‑state memory.
05 Mar 2026, 19:44 UTC

Problem: Keeping UI state in sync without full page reloads
When building a Vaadin Flow application you often need to switch between screens (views) while preserving the single‑page‑app feel. Manually manipulating the browser history or writing custom JavaScript routers adds complexity and can break Vaadin’s automatic client‑server synchronization.
Thesis: Vaadin’s built‑in navigation API lets you define views as plain Java classes and move between them with a single method call, giving you type‑safe URL handling and SPA‑style updates.
How views are mapped to URLs
Any Java class annotated with @Route becomes a navigable target. Vaadin derives the URL segment from the class name (or a custom value) and registers it at startup. No extra routing configuration files are required.
@Route("dashboard")
public class DashboardView extends VerticalLayout {
public DashboardView() {
add(new H1("Dashboard"));
}
}
@Route("settings")
public class SettingsView extends VerticalLayout {
public SettingsView() {
add(new H1("User Settings"));
}
}
Visiting http://localhost:8080/dashboard renders DashboardView; /settings renders SettingsView.
Programmatic navigation
To move from one view to another you call UI.getCurrent().navigate(String target). The call updates the browser URL via the History API and swaps the view content without a full page reload.
Button goToSettings = new Button("Open Settings", e ->
UI.getCurrent().navigate("settings"));
add(goToSettings);
You can also use an Anchor component for declarative links:
Anchor settingsLink = new Anchor("settings", "Go to Settings");
add(settingsLink);
Typed route parameters
When a view needs data from the URL, add @RouteParameter to its constructor. Vaadin extracts the value and passes it in, giving you compile‑time safety.
@Route("user")
public class UserView extends VerticalLayout {
public UserView(@RouteParameter("id") String userId) {
add(new H1("User "+ userId));
}
}
Navigating to /user/42 injects "42" as userId. If the parameter is missing, Vaadin triggers a BeforeEnterEvent that you can handle to redirect or show an error.
Trade‑off: Server‑side view state and memory usage
Each view instance lives in the Vaadin session. With many concurrent users, especially if views hold large components or data, memory consumption can grow. To mitigate:
- Use
@PreserveOnRefreshonly when you truly need to keep state across a browser refresh. - Scope lightweight views as
@Routewithout preservation; Vaadin will create a new instance on each navigation. - Consider view‑level lazy loading with
@RouteAliasto share the same class for multiple URLs while keeping instances separate.
Monitoring session size (e.g., via JMX or a simple servlet filter that logs HttpSession#getMaxInactiveInterval()) helps you spot growth early.
Verification steps you can run today
- Create a Vaadin Flow project (start.vaadin.com) using the latest LTS.
- Add the two view classes shown above.
- Run the application and navigate manually to
/dashboardand/settings; observe that the URL changes and the view swaps without a full reload (check the Network tab for XHR/fetch calls to the internal VAADIN endpoint). - Click the "Open Settings" button; verify the URL updates to
/settingsand the SettingsView appears. - Navigate to
/user/123and confirm the heading shows "User 123".
These steps confirm that the navigation API works as described; they do not guarantee performance under load, which you should test separately.
Actionable closing
Vaadin Flow’s navigation lets you keep routing logic in Java, enjoy type‑safe parameters, and get SPA‑style updates without extra frontend tooling. Start by annotating your views, use UI.getCurrent().navigate for programmatic moves, and add @RouteParameter where needed. Keep an eye on session memory, and apply @PreserveOnRefresh judiciously. With these patterns you can build maintainable, URL‑driven Vaadin applications that feel responsive to users.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.