Using Vaadin Flow’s @Push to Enable Server‑Side UI Updates Without Polling
Discover how Vaadin’s @Push annotation turns a classic request‑response web app into a real‑time experience, the setup steps, a working example, and the trade‑offs you need to consider.
23 Dec 2025, 03:34 UTC

Problem: The Classic Request‑Response Loop
In a traditional Vaadin Flow application the client sends a request, the server processes it, and the updated UI is rendered back to the browser. When you need to push data from the server—like a live chat, a stock ticker, or a sensor feed—the only option is to have the client poll the server or implement a custom long‑polling mechanism. Both approaches add latency or unnecessary traffic.
Thesis: @Push Turns the Server Into a Publisher
The @Push annotation activates Vaadin Flow’s built‑in WebSocket support. Once enabled, the server can send UI changes to the client immediately, without the client initiating a request. This turns a passive UI into a real‑time, event‑driven component while preserving Vaadin’s stateful session model.
How to Enable @Push
- Check the Environment
- Servlet container: Tomcat 9+, Jetty 9+, or any servlet 3.1+ compliant server.
- Vaadin Flow version: ≥ 14.0.
- HTTPS is required for browsers that block mixed content; otherwise the WebSocket connection will fail.
- Add the Annotation
@Push @Route("/dashboard") public class DashboardView extends VerticalLayout { // UI components and logic }Place the annotation on the UI class that should receive push events. If you need a single WebSocket per user session, use
@Push(true)to share the connection across all UIs in that session. - Deploy and Verify
- Run the application in a servlet container.
- Open
https://localhost:8443/dashboardin Chrome. - Open the browser console and look for a WebSocket connection to
/vaadinServlet/PushServlet.
Concrete Example: A Live Counter
Below is a minimal Vaadin Flow view that increments a counter on the server every second and pushes the new value to the client.
@Push
@Route("/counter")
public class CounterView extends VerticalLayout {
private final Label counterLabel = new Label("0");
private final AtomicInteger counter = new AtomicInteger();
public CounterView() {
add(counterLabel);
// Start a background task that updates the counter
Executors.newSingleThreadScheduledExecutor().scheduleAtFixedRate(
() -> {
int newValue = counter.incrementAndGet();
// UI updates must run on the UI thread
UI.getCurrent().access(() -> counterLabel.setText(String.valueOf(newValue)));
},
0, 1, TimeUnit.SECONDS);
}
}
When you open the page, you’ll see the number jump up every second without any button clicks or page reloads. If you comment out the @Push annotation and reload, the number will stay static until you perform a client‑side action that triggers a server round‑trip.
Trade‑Offs and Limitations
- Browser Support: WebSocket is widely supported, but older browsers fall back to long‑polling, which can degrade performance.
- Server Load: Each UI update sends a message over the WebSocket. If updates are frequent, consider batching or throttling to avoid overwhelming the server.
- Clustering: In a multi‑node environment, the PushServlet must be shared or the session must be replicated; otherwise push messages may be lost for users connected to a different node.
- Security: The WebSocket endpoint inherits the same security constraints as the main servlet. Ensure proper authentication and authorization checks are in place.
Actionable Checklist
- Verify your servlet container meets the minimum version.
- Add
@Push(or@Push(true)for session‑wide sharing) to the UI class. - Deploy over HTTPS and confirm the WebSocket connection in the browser console.
- Test a simple push scenario (e.g., a timer or button click) to ensure the UI updates instantly.
- Measure server load under realistic traffic and implement throttling if necessary.
- In a clustered setup, ensure the PushServlet is accessible from all nodes or enable session replication.
Conclusion
The @Push annotation is a lightweight, framework‑native way to add real‑time capabilities to a Vaadin Flow application. It eliminates the need for external libraries or custom polling logic, keeps the server‑side state intact, and integrates cleanly with Vaadin’s UI thread model. By following the steps above and being mindful of the trade‑offs, you can deliver a responsive, push‑enabled user experience with minimal overhead.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.