Java GUI framework: Swing vs JavaFX vs web with webforJ

If you want to keep writing Java and you are picking a Java GUI framework today, webforJ is the option that gets you a browser-delivered UI without leaving the language. You build screens from Java classes, run them on the server, and users open a URL. Swing and JavaFX remain the choice when the app must work offline. If offline isn't a requirement, a webforJ app can be installed too, so it sits on the desktop, home screen or app menu like a native app.
The decision is mostly about delivery. Swing and JavaFX put the UI on each user's machine. A web UI written in Java puts it on one server and shows it in a browser. This post compares the three on the questions that change the outcome, then shows what the same button handler looks like in Swing and in webforJ.
Swing, JavaFX and web at a glance
| Question | Swing | JavaFX | Web UI in Java (webforJ) |
|---|---|---|---|
| Where the UI runs | On the user's machine | On the user's machine | On the server, rendered in a browser |
| How users get it | An installer or a launcher | An installer or a launcher | A URL |
| Updating | Redeploy to every machine | Redeploy to every machine | Deploy once |
| Platforms | Desktop operating systems with a JVM | Desktop, with mobile and embedded targets | Any device with a browser |
| Look and feel | Java toolkit components | Java toolkit components | HTML, CSS and web components |
| UI thread | Event dispatch thread | FX thread | One server thread per session |
The sections below take each row in turn.
Distribution and installation
Swing ships in the JDK. The java.desktop module defines the AWT and Swing toolkits, so a Swing app needs nothing beyond a Java runtime. JavaFX is distributed separately as OpenJFX, through Maven modules or a standalone SDK.
Either way, you still have to get the program onto each machine. The JDK's jpackage tool builds native installers (exe and msi on Windows, pkg and dmg on macOS, deb and rpm on Linux) and bundles a runtime. Its documentation states that app packages must be built on the target platform, so supporting all three operating systems means running the packaging step on each.
A webforJ app has no installer for end users. It is a Spring Boot JAR or a WAR, and users reach it by URL. If you want an icon on the home screen or desktop, @AppProfile generates a web app manifest so supporting browsers can install the app, and the installable apps post shows the result.
Updates
With a desktop client, every release is a rollout. You build installers, publish them, and wait for users to take the update. Versions drift, and support has to know which build each person runs.
With a server-rendered UI, a release is a deployment. The next page load serves the new code to everyone, so the version on the server is the version in use. For internal business apps, where the people who need a fix are the same people filing the ticket, this is often the whole argument.
Platforms and mobile
Swing targets the desktop. OpenJFX describes itself as a platform for desktop, mobile and embedded systems, so JavaFX gives you a path to more form factors, though each target brings its own build and packaging work.
A webforJ app reaches any device that has a modern browser. The same views serve a laptop and a phone. ColumnsLayout is responsive by design, calculating how many columns to show from the width of its container, and the component catalog lists the rest.
Look and feel
Swing's own documentation says its components are lightweight and, to the maximum degree possible, work the same on all platforms. That consistency is also why a Swing app reads as a Swing app. The module also exports javax.swing.plaf, the pluggable look-and-feel API, for changing it.
A web UI uses the browser's rendering stack. webforJ components are web components, so theming is CSS custom properties and shadow parts. The framework ships light, dark and dark-pure themes and one @AppTheme annotation selects the default. Brand colors, spacing and typography are tokens you override, as the themes documentation describes. Your designer's CSS knowledge applies directly.
Threading model
Both desktop toolkits have a single UI thread you must respect. Oracle's Swing tutorial says that Swing component methods other than those labeled thread safe must be invoked from the event dispatch thread, and background work reaches the UI through invokeLater. JavaFX has the same shape, with Platform.runLater posting a Runnable to the JavaFX UI thread.
webforJ also enforces one UI thread, per user session. Events are processed sequentially on it, so handlers don't race each other. When a background task needs to update the UI, Environment.runLater() schedules the update back on that thread. It is documented as experimental, and the asynchronous updates guide covers its use. The mental model is the one you already have from Swing, with the extra fact that the UI thread lives on the server.
What the same handler looks like
Swing:
public class SwingSave {
private final JLabel status = new JLabel();
public JButton build() {
JButton save = new JButton("Save");
save.addActionListener(e -> status.setText("Saved"));
return save;
}
}
webforJ:
@Route("save")
public class WebSave extends Composite<Div> {
private final Paragraph status = new Paragraph();
public WebSave() {
Button save = new Button("Save", ButtonTheme.PRIMARY);
save.onClick(e -> status.setText("Saved"));
getBoundComponent().add(save, status);
}
}
The listener is the same lambda. The component is a Java object that you construct, then add to a container. The difference is that @Route("save") makes this class a page with its own URL.
Which desktop skills carry over
Most of what you know from Swing transfers.
- Listener-based events become
onClick(...)and the otheronmethods. See the events guide. - Layout managers become
FlexLayout,ColumnsLayoutandAppLayout. - Model objects stay as plain Java beans, and
BindingContextplays the role a form-binding layer would. The data binding docs have the details. - A table over a collection becomes a
Tablebound to aRepository. - Your services, validation and domain classes stay as they are. Under Spring Boot they are injected into views through the constructor.
What you stop writing is the code that moves data between a client and a server. The Spring Boot without a REST API post explains why that layer drops out when both sides are Java.
Teams moving off Swing
webforJ fits teams that have a Swing app and need it on the web. You don't have to start with a rewrite. Webswing runs Swing, JavaFX or SWT apps in a browser without modification, and the WebswingConnector component embeds that app inside a webforJ page. New screens are written in webforJ beside it, and old screens retire one at a time. The Webswing modernization roadmap lays out the stages, and the modernization tutorial builds one on a Swing customer app.
The same pattern applies to server-rendered legacy pages. The JSP modernization post shows how a JSP page becomes a component tree.
Which Java GUI framework should you choose?
Choose Swing or JavaFX when the program must run offline or drive local hardware. Being installed is not a reason on its own, since a webforJ app can be installed from the browser as well. Choose webforJ when users are on different devices, when you want one deployment instead of many installs, or when your app is a business system that people reach from a browser. You keep the language, your build tool, and your Spring services, and you add delivery to every device that has a browser.
To try it, generate a project with startforJ or follow the getting started guide.
Frequently asked questions
Is Swing still used?
Yes. Swing is part of the JDK's java.desktop module, and many enterprise desktop apps still run on it. Teams that want those apps in a browser can keep them running through Webswing while they build new screens in webforJ.
Is JavaFX better than Swing?
JavaFX is distributed as OpenJFX with a stated path to mobile and embedded targets, and Swing ships with the JDK. Neither removes the work of installing and updating a desktop client. A web UI removes that work.
Can I build a web UI in Java without writing JavaScript?
Yes. In webforJ you build views from Java components, route them with @Route, and style them with CSS. When you need a third-party web component, ElementComposite wraps it as a Java class.
What replaces Swing for new Java applications?
It depends on delivery. For a desktop program that must work offline, JavaFX is the toolkit built for that. For an app that people open in a browser on any device, a web UI written in Java with webforJ keeps your team in Java.
Building something with webforJ?
Talk to the team about your project, a migration, or whether webforJ fits.



