Real‑Time UI Updates in Vaadin Flow with @Push: How, Why, and When to Use It
Learn how to use Vaadin Flow’s @Push annotation for real‑time UI updates, from enabling the feature to a minimal example, and understand the trade‑offs and best‑practice checklist before deploying it.
09 Apr 2026, 09:45 UTC

Why Push Matters for a Vaadin UI
In most Vaadin applications the server sends a response to the client only after the user performs an action – a button click, a form submit, or a navigation. That round‑trip introduces a small but noticeable delay. If you need the UI to react instantly to background events (e.g., a sensor update, a message queue, or a scheduled job), you can turn the server into a publisher. Vaadin Flow’s @Push annotation opens a WebSocket channel that lets the server push changes to the client without waiting for a user request.
Enabling Push: Where and How
Push can be turned on in two places:
- Globally – add
vaadin.push.enabled=truetoapplication.properties. This activates push for everyUIinstance. - Per‑UI – annotate a
@Routecomponent with@Push(PushMode.AUTOMATIC)or@Push(PushMode.MANUAL).PUSHMODE.AUTOMATICsends updates whenever a component state changes;PUSHMODE.MANUALrequires explicit calls toUI.access().
Both approaches rely on the servlet container’s WebSocket support. If WebSockets are unavailable, Vaadin falls back to long‑polling, which is slower and increases latency.
Minimal Working Example
Below is a self‑contained example that demonstrates push in a background thread. It runs on any servlet container that supports WebSockets (Tomcat 9+, Jetty 9+, WildFly 21+).
@Route("push-demo")
@Push(PushMode.MANUAL) // or AUTOMATIC for auto‑push
public class PushDemo extends VerticalLayout {
private final Label status = new Label("Waiting for update…");
private final UI ui;
public PushDemo() {
ui = UI.getCurrent();
add(status);
startBackgroundTask();
}
private void startBackgroundTask() {
// Run a task every 5 seconds in a separate thread
Executors.newSingleThreadScheduledExecutor()
.scheduleAtFixedRate(() -> {
// Simulate data change
String newText = "Updated at " + LocalDateTime.now();
// Must schedule UI update on the UI thread
ui.access(() -> status.setText(newText));
}, 5, 5, TimeUnit.SECONDS);
}
}
When you navigate to /push-demo, the browser opens a WebSocket connection to /push. Every five seconds the background thread calls UI.access(), which queues a UI update. The client receives the message instantly and refreshes the label without any user interaction.
How to Verify Push Is Working
- Open the browser’s developer tools, go to the Network tab, and filter by
push. You should see aGET /pushrequest with a101 Switching Protocolsresponse. - Check the console for a message like
PushChannel createdorPushChannel closed. Those logs appear when the server opens or closes a WebSocket. - Observe the label on the page. It should change automatically every five seconds.
Trade‑Offs and Limitations
While push gives a smooth real‑time experience, it comes with costs:
- Resource usage – Each connected client keeps a WebSocket open, consuming memory and a file descriptor. In a high‑traffic app, this can saturate the servlet container.
- Scalability – In a clustered environment you need sticky sessions or a shared push channel (e.g., via a message broker) to keep state consistent across nodes.
- Security – The push endpoint is public by default. Ensure you restrict access (e.g., via servlet‑container filters or Vaadin’s
SecurityContext) to prevent unauthorized clients from listening to push streams. - Proxy compatibility – Reverse proxies must support the WebSocket upgrade handshake. If they don’t, Vaadin silently falls back to long‑polling, which may degrade performance.
When deciding to enable push, consider the expected number of concurrent users, the server’s capacity, and the deployment topology. For small to medium apps, the default WebSocket approach works fine. For larger deployments, evaluate load‑balancing strategies and possibly use a dedicated push broker.
Practical Checklist Before Going Live
- Confirm the servlet container supports WebSockets (Tomcat 9+, Jetty 9+, WildFly 21+).
- Test the WebSocket handshake in the target environment – proxy, load balancer, CDN.
- Monitor the number of open connections (e.g.,
netstat –an | grep 80or application logs). - Set
vaadin.push.enabled=trueonly if you need push globally; otherwise use per‑UI@Pushto limit the scope. - Secure the push endpoint (configure authentication or IP whitelists).
When to Skip Push
If your application only needs occasional updates triggered by user actions, or if you have strict resource constraints, you might opt for traditional polling or manual UI refreshes. Push is most beneficial when:
- Updates are frequent and user‑centric (e.g., chat, live dashboards).
- Latency matters – you want to avoid the round‑trip delay.
- The user base is moderate and the server can sustain the WebSocket load.
Conclusion
Vaadin Flow’s @Push annotation is a lightweight, built‑in way to deliver real‑time UI updates. By enabling it locally or globally, configuring the push mode, and following the verification steps above, you can add instant responsiveness to your application. Just remember to weigh the resource consumption, scaling implications, and security requirements before turning on push in a production environment.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.