In 2013 I was writing full-stack Java at BluLogix, compiling to JavaScript with Google Web Toolkit, wiring up Spring Security for auth, and shipping a cloud billing platform for telecom operators. TypeScript would not hit 1.0 for another year. React was a Facebook-internal thing. Node.js was what people wrote blog posts about, not what they shipped billing systems on.
I was, without knowing it, doing type-safe full-stack development a decade before it became the default.
What GWT actually was
Google Web Toolkit (GWT) was an audacious idea: write your frontend in Java, run the GWT compiler, and get optimized JavaScript out the other side. Not a thin wrapper. Not some JSX analog. Java — classes, generics, interfaces, the full type system — compiled via cross-compilation to JavaScript that ran in the browser.
This worked because Google needed it to work. Gmail was built on GWT. Google Docs was built on GWT. Google threw serious engineering at the compiler — dead-code elimination, code splitting, permutation-based optimization across browser targets — and it produced surprisingly efficient output. The resulting JS was minified and permuted per browser, so IE got one artifact, Firefox got another, Chrome got another. You did not have to care about that. The compiler handled it.
The value proposition for a team like mine was immediate: the same
type system protecting your backend was protecting your frontend. If
the API returned a BillingCycle object, the UI code received a
BillingCycle object, with all its fields typed, and the compiler caught
every mismatch at build time. No JSON shape mismatches. No “I thought
that field was a String.” No runtime surprises because someone renamed a
property in the backend DTO and forgot to update the frontend fetch call.
In 2013, this was genuinely unusual. Everyone else was writing jQuery callbacks and praying.
The price you paid for static types
GWT was not free. The compiler was slow. Not “a few extra seconds” slow — compile cycles on a mid-sized GWT app ran two to five minutes. The incremental dev mode (where you ran the app in a hosted browser and hot- swapped Java bytecode) helped, but it was fragile: dev mode and production compilation sometimes diverged in subtle ways, and you’d ship something that worked perfectly in dev and broke in a permutation the dev browser never exercised.
The widget model was Java-style object hierarchies: GwtWidgets that
extended abstract base classes, event handler interfaces, UiBinder
XML templates that mapped to Java classes. This was 2013 Java enterprise
culture applied to UI. It felt natural if you came from Swing or JSF. It
felt alien if you came from anything else.
CSS was a genuine fight. GWT’s CssResource system gave you type-safe
CSS class names — your Java code would reference myStyle.myClassName()
instead of a raw string, so renaming a CSS class would produce a
compiler error rather than a silent break. This is actually great in
theory. In practice, the tooling around it was rough enough that I spent
meaningful hours debugging why a style wasn’t applying, only to find
I’d referenced the wrong CssResource type.
Spring Boot showed up and it felt like a gift
I started using Spring Framework around 2012 — Spring MVC for REST
endpoints, Spring Security for auth, Spring WS for SOAP services (yes,
SOAP, this was enterprise Java for telecom). This was the era of
XML-configuration Spring: applicationContext.xml files that were 500
lines of bean definitions, namespace declarations, and property
placeholders. You had an intimate relationship with your application
context. You knew every bean by name.
Spring Boot 1.0 shipped in April 2014. I was at AFAQ by then, and we adopted it early — early enough that there weren’t yet 400 Stack Overflow answers for every configuration problem you hit.
The shift Boot made was not adding features. It was eliminating
ceremony. Auto-configuration meant the framework guessed reasonable
defaults from your classpath and wired up what you actually needed.
@SpringBootApplication replaced the XML maze. Embedded Tomcat meant
you ran java -jar instead of managing a container deployment.
application.properties replaced a third of your XML.
The first time I ran a Spring Boot app from scratch and had a working REST endpoint in under 10 minutes — not counting the time to read the docs on what I was doing — I understood that something had changed. Not technically revolutionary. Philosophically different.
Building the AFAQ EHR on GWT + Spring Boot
At AFAQ (2014-2017) I was building an EHR/EMR suite — web-based, fully integrated with ERP modules, deployed on top of components from VA VistA. The tech stack: GWT on the frontend, Spring Boot + Java EE on the backend, with the VistA MUMPS components behind a service layer (I have a whole other post about that side of it).
The specific combination of GWT and Spring Boot was actually quite good
for healthcare. Here’s why: healthcare UIs are complex, stateful, and
high-stakes. A patient chart view has nested tabbed panels, real-time
lab result feeds, medication lists that update during the session,
encounter notes with rich text, and alert badges that have to fire when
something changes. GWT’s Java UI model handled this better than jQuery
spaghetti. The type safety mattered when the data was AllergyRecord and
MedicationOrder objects rather than arbitrary JSON.
Spring Boot’s opinionated defaults also helped at AFAQ because the team was not large and we needed to move fast. Convention over configuration let us write the business logic instead of debating bean lifecycles.
The pain point was the build. A full GWT compilation on the frontend, plus Spring Boot’s Maven build on the backend, on 2014-era hardware, was a 15-minute process from clean checkout to deployable artifact. We had to be disciplined about not breaking the build, because the feedback loop from “I merged something wrong” to “I know it’s broken” was quarter of an hour at minimum.
Why GWT is gone and what replaced it
GWT peaked around 2012-2013 and then JavaScript got better, fast. TypeScript arrived and gave the JavaScript world the static typing GWT had always been selling. React gave it the component model. Webpack gave it the code splitting. The build tooling improved dramatically. And critically: every web engineer already knew JavaScript. The pool of people who could write GWT Java frontend code was the intersection of “Java engineers” and “people willing to write frontend” — a famously small Venn diagram.
Google gradually reduced its investment in GWT. The community took it over. New development in GWT is now niche-within-niche: there are medical billing systems still running it, enterprise Java shops that never migrated, and a handful of open-source projects that use it.
Spring Boot, by contrast, went the other direction. It ate the Java backend world. If you’re writing a new Java service in 2024, you are almost certainly using Spring Boot. It became the default in a way few frameworks do.
The irony is that the part of the stack that was less novel (Java backends have existed since 1997) turned out to be the durable one. The part that was genuinely ahead of its time — type-safe compiled frontend Java — lost to the ecosystem it was competing against once that ecosystem matured.
What I’d tell someone hitting the GWT nostalgia wall
If you worked in GWT and feel wistful about it: what you’re actually missing is the feeling of a consistent type system across the stack. That feeling is now available in TypeScript + tRPC, or in a full Java backend with a generated TypeScript client, or in Kotlin + Compose Multiplatform if you’re feeling brave. The tooling is dramatically better.
But you’re not wrong that GWT solved a real problem first. It solved it with a lot of Java, a very slow compiler, and a widget model that looked like Swing. In 2013 that was the right trade. In 2024 you have better options — and most of those better options exist because GWT existed first, demonstrated the value, and paid the experimental tax so everyone else could build something cleaner.
I still think about the GWT UIBinder XML templates occasionally. Not
fondly. But with a specific kind of respect reserved for things that
were genuinely hard and that I shipped to production anyway.
Spring Boot I think about every day. It’s in my stack right now.