JCON EUROPE

The Road Not Taken: A Developer's Guide to Life Beyond Spring Boot | Frederik Pietzko (EN)

46:52 · 20 Apr 2026 – 23 Apr 2026 · YouTube

About this talk

In this talk, Frederick Piitzko explores the advantages and drawbacks of various frameworks for building Java applications, focusing primarily on Spring Boot, Quarkus, Micronaut, and several others. He shares his experience with Spring Boot, emphasizing its strengths but also acknowledging performance concerns in larger applications. The speaker presents benchmarking results based on simple RESTful APIs built using different frameworks and highlights the benefits of using Quarkus alongside Hibernate with Panache, as well as JDBI for performance improvements. He discusses the structured concurrency model used in Ktor and compares the developer experiences across frameworks, ultimately favoring Quarkus for its ease of use and integration capabilities. In the concluding remarks, Piitzko touches on micro-frameworks like Javalin and HTTP4K, noting their use cases and performance in various scenarios.

Full transcript

[music] >> First, I want to introduce myself a little bit. My name is Frederick Piitzko. I work for an IT consulting company called IITS. We have a booth here, so if you go outside, straight to the right, we have a small booth there. And if you want to chat with me afterwards, you can find me there, probably. Um, and at the end of this talk, we have

like one plushy left. So, at the end of this talk, I will throw it somewhere, and if you catch it, you can keep it. It's the last one we have. His name is It's by the way, it's not a fox, it's a red panda. It's important to me to mention that. His name is Kumo. So. first I need to start out with a disclaimer. I actually love

Spring Boot. Um, I have used it throughout my career, and I will continue to use it throughout my career very happily. And I earn most of my money by writing Spring Boot applications. But, it is It It has a couple of downsides, and it is worth exploring what's what else is there. Especially when you have a bigger application, or you do stuff on startup, some some dynamic

bean registration, or if you have Spring Data JPA inside of your project, uh, come with Hibernate, then, um, startup times can get brutal quite easily. It has gotten better, especially in like development, thanks to development mode. Um, but still, right? You can optimize all of that uh, with Spring AOT and GraalVM, uh, but those are also a pain, and or sometimes a pain. It depends on what

your application is actually doing. I have some more disclaimers. Uh I did some benchmarking and I will show the benchmarking result at the end. I did not do professional benchmarking and that was not really the goal of this. Uh what I wanted to actually capture is basically the idea of, "Hey, I've just read a tutorial or watched a YouTube tutorial or something about a framework or read

like the getting started documentation developed a small application and that's what I'm actually benchmarking. So, none of those benchmarks are none of the frameworks I have benchmarked I've tuned anything. I've not touched it its default settings and um yeah. So, it's it's not uh tuned to perform particularly good in the benchmark, right? And this is what I implemented as a quick overview. It's just a small uh

REST API kind of a pet clinic situation going on here. I have an endpoint to get all of the visits. I have another endpoint to get the visits by ID and then I have a post endpoint to create a visit, right? In this case for a cat that is throwing up too much. The cat owners will probably know this. Any cat owners here, by the way? Nice.

You are my friends now. Okay. Um first I will talk about Quarkus. It's the one framework that probably knows most people know and the first one that comes to mind when we are talking about anything enterprise related that is not Spring Boot. Any avid Quarkus users here? One in the back. Okay. and in this case in combination with Hibernate, although not like stock Hibernate or stock JPA,

but small library called Panache. I hope I pronounced that correctly, but I assume that's what it should be pronounced pronounced like. It's a small layer on top of JPA and Hibernate developed by the Quarkus team. And it offers let's call it simplified access via the active record pattern. Do you guys know the active record pattern? Okay, I will show it to you. Now this is how one

of those entities looks like. It looks pretty stock standard like a JPA entity should except it extends Panache. This Panache entity. It's an abstract class. It provides by a long as an ID. And it offers a bunch of static methods defined on there to actually query the database. And that's the active record Yeah, explained in a nutshell. like a quick comparison on how on how a rest

controller or in this case a rest resource would look like. It looks a little bit different than what you would expect from Spring or no from Spring because it doesn't use these Spring annotations. But it uses Jakarta EE and Jakarta rest for web services. And that's where all of these like path annotation comes from. The transactional one is also just the one from Jakarta AE. So it

does the exactly the same thing that you know. and like the path and producer stuff. And you can also see the active record part here, right? So I can just call functions like stream all directly on this visit entity. And you can also like combine it do more complex queries. You can create your own static methods on the entity that do more complex stuff, right? And it's

a nice pattern to use. It I have to Panache also supports the more standard repository pattern if you so choose, right? That's also absolutely possible. Now, uses Jakarta specifications a lot and almost exclusive or pretty much exclusively and simplifies them in a lot of places, right? Because the like JPA for instance, if you use raw JPA to this day, you need to write a persistence.xml. You don't

have to do that in Spring, you don't have to do that in Quarkus, and you also don't need to do that in Micronaut. Um, it also uses CDI for dependency injection instead of having it's instead of doing it like Spring and provide their own dependency injection ideas. Quarkus is also very cool to um compile to native. It has one of the best integrations for GraalVM and does

a lot of ahead-of-time code compilation to facilitate that. And one thing I discovered by doing all of this, and this may be interesting, is that Quarkus doesn't use Hikari as a connection pool, but something called Agro. I never heard of it before, uh, but it looks to be somewhat similar, although it's less known. because I did some benchmarking, I noticed that this implementation here has an N+1

problem. So, if I call the fetch all endpoint and I do a stupid like here stupid stream all, uh, the way these annotations works is is that it causes an N+1, which is unfortunate, right? Because it ends up because it causes Quarkus to score, at least with compared with Hibernate, to score super low on my benchmarks. So, I was like, "Okay, yes, but I want to keep

it because it's this stupid thing that happens if you just watch a tutorial and never used these tools before. It's also the kind of thing an AI agent will do. Um so, be aware of that. So, I implemented Quarkus a second time with JDBI. Does anyone know JDBI? It's a pretty cool thing. Uh I assume you know Spring Data JDBC. So, day Spring Data JDBC came first,

and JDBI is basically what spr- feels like what um JBI feels like what Spring Data JDBC would have been were it developed today by Jakarta people. It's not from the Jakarta people, but it's similar. Um and you can do stuff like this, right? Uh you are able to write your SQL by hand and have some magic create an actual implementation for you. >> [snorts] >> Um there

is a difference. Uh Spring Data JDBC and all the Spring Data stuff, they will create the actual implementations of your repositories at runtime on startup, right? And JDBI actually is generates them at compile time. And which which is quite nice, in my opinion. And I was recently told there are more options than just to use SQL object. Uh and so, there are more ways to use it

than I did. This was just the one that's most similar to to um Spring Data, I'd say, right? There is, unfortunately, no really good way to map uh join into a projection apart from doing what I did, like putting it into a join row and then um providing a default implementation that actually does that. But, it's it's relatively cool. Uh you need to define bean matters and

register them. Those So, you don't really need to create the matrices yourself, but you need to register the classes that need to be mapped. Right? Uh that is what makes it possible to call row.get and actually get the an instance of my class, and it will be mapped automatically. Um it's really lightweight, and I enjoyed using it, although it's a little bit more verbose than what you

would see with Spring Data. Now, let's move on to Micronaut. Who knows Micronaut? Who uses it in production? Anyone? No one. Okay. Well, I think you should. Um Micronaut is very similar to Quarkus in that it also focuses on open standards. Right? So, it also uses the whole Jakarta EE stuff. It also leverages CDI. It also leverages JPA and um the Jakarta RESTful Web Services. >> I

also implemented that one twice, by the way, but I'm only going um I'm not going to show the Hibernate one. For fairness, it also has the N+1 Uh but, what I'm going to show instead is the Micronaut Data JDBC, which is essentially a clone of Spring Data JDBC, uh but it instead will precompile everything. So, it will generate the repository at compile time, as well. that And

it forces you to annotate your repository with the dialect you're using, right? Because they're doing it before and you can similar to Spring, which wouldn't matter if you are doing just queries like that, right? Then you are then you use the dialect you're using. Uh, but if you have like magic method names like a find all or something, it needs to know which dialect to generate. And

another difference is that you need to annotate everything that needs to be serialized. So, database if you map a database row into a projection or you at least if you want to uh, that to happen automatically like I'm doing right here. Um, you need to annotate it with serdable. Because that mapping logic will also like it will get generated at compile time instead of at runtime. So,

as I said this this isn't really much different from the Quarkus example. That is because it also uses Jakarta Uh, so not really a big surprise there. Um, this time since it's not the active record pattern, I'm actually using constructor injection. I was also lazy and used Lombok to fit everything on the slide. And so not not really anything that would probably surprise you if you used

the Jakarta RESTful Web Services before. And I mentioned everything that needs to be serialized needs some sort of annotation. The same is true for anything that you want to transform to JSON. Right? So, you need to put these @Serdable, @Serializable annotations on you want to serialize and if you have like nested nested classes inside, you need to also provide this annotation on Okay, and with that, we

already leave the comfortable land of these big three. Uh now it becomes a little bit obscure. Um of these three, my favorite is still Spring Boot, uh but I'm probably biased because I use it the most. Uh Quarkus, although, is a very very strong second place place. Oh, I forgot to mention, uh Quarkus has something called the Quarkiverse, which is a open community where that everyone can

contribute to and offers a lot of integrations for Quarkus. So, you can also go ahead and take the Spring dependency injection annotations, for example, and use them in Quarkus through a Quarkiverse plugin, which is crazy. So, and Quarkus easily has one of the best developer experiences out there. They have a concept called dev containers, which is different from the dev containers you used to develop in, um

but instead, uh if you have like uh PostgreSQL driver on your classpath, but uh you didn't configure any data source, it will just start a PostgreSQL container for you and wire up it up automatically under the hood. It also has an amazing dev UI, which one can use, which I forgot to mention earlier. So, next, the the obscure ones. Has anyone seen this logo before? One person.

Do you want to shout what it is? >> I don't know the name. >> It's Helidon. Helidon is uh like Micronaut, maintained by Oracle and it's pretty interesting. Helidon is both a server as well as a framework. And the framework even comes in two editions. Since Helidon 4, the server is to me the most interesting part. The concept is as follows. Take all of the super old

Java networking APIs from like Java 1.1 and 1.2 and 1.3 like those Build a server from scratch that's not a servlet thing, right? It doesn't use the servlet API, but like a standalone and combine it with virtual threads. And see if that works and if it goes fast. Turns out it turns it it goes pretty fast. It's a very very fast server. then there's the framework on

top of it which comes in two flavors. One of them is MP, short for microprofile. It is essentially a worse version of Quarkus or micronaut. So it uses all the Jakarta EE and microprofile specifications while not having a good documentation and while not automating your persistence XML or your beans XML for example. So you need to do all of that yourself. Which is kind of annoying nowadays.

So I don't recommend Helidon MP to anyone. I'm sorry if someone from the Helidon team might watch this at some point. If there's I don't know if I don't know if this is actually being recorded, but yeah. So it's it's not great. Then there's standard edition. The the denomination is a bit um weird because standard edition is not that standard. It's not what you know from those

classical enterprise frameworks. Instead, it's a microframework and it is super minimal and it used to be reactive and based on channels. It is no longer. You still see it in some points because it uses stuff like the like the reactive PostgreSQL driver if you do DB access towards PostgreSQL, but you don't really feel the reactiveness of it because it just uses virtual threads and thus unblocks all

of your normal IO operations. >> So, this this looks like this. It's a microframework. It's super minimal, right? This is their DB client. They have their own DB client, so they don't rely on JDBC or R2D or R2DBC, but they develop their own thing. you need to do everything yourself. So, you need to do your transactions your transactions yourself. You need to do your row mapping yourself

to map everything into records. comes at the cost of being very manual and you needing to have to do And I really mean everything. I'll show But, it also means that super fast. You also need to do routing yourself. Right? So, I have somewhere in this code example a static function called routing which accepts a builder and ignore the application context. That's just me trying stuff out.

And then you need to register any class that implements the HTTP service. And it could also just be a function, The HTTP service itself you need to have one one thing here which is routing, right? And then you do your actual routing. You have your standard HTTP verbs. You have the the path pattern it looks for and then you can just put put like a function pointer

in there. So, no fancy annotations to set up your routing for you. You need to do it yourself. And you need to do even more yourself. This is maybe a little bit small, so I'll zoom in. First, you need to create your own object mapper. A spring and Quercus and micronaut all do this for you out of the box. You don't worry about serialization at all. Here

you need to worry. So, you start creating all of them. If you want observability, well, you need to set that up yourself. You need to create a metric metrics observer. I mean, in this case it's the standard micrometer stuff and I did not configure anything special. Yeah, you need to configure media support, right? So, you need to configure hey, yeah, I'm I'm actually using Jackson and here's

the object mapper. By the way, and yeah, the routing. Also, don't forget to call start, otherwise it will just exit, right? It doesn't wait or anything. >> Now, I have a quick side tangent because now I'll go be entering the realm of Kotlin with the next couple of micro frameworks and because I'm not the biggest lover of hibernate, I decided to use Well, it's not really an

ORM, more of query SQL query builder called exposed. It's developed by JetBrains and it is quite nice. I like to use it. and I will use it for the next What is it? Three micro frameworks. you can in exposed you can declare tables like this as objects. Think of objects just as a singleton that lives in the global scope of your application. And you can define columns

on there like so, right? So, those are long ID tables, they have a long ID, obviously. Um and you can also do foreign keys, like so, to then later join on them. Now, what makes it cool is that it is type safe. It also forces you to map result rows manually. Uh but, as well as like the updates manually, but it does though in as type safe

as type safe as possible manner. So, this is a insert and get ID, right? Uh I I think you will probably know what the SQL that results of that is the result of this uh function will look um but I still need to wrap to to actually map the row myself. And to do that, I can I can take this row and then start mapping values into

it. This name is exactly defined like so on the on the tap uh on the pet table, and it is there, and it is accessible because of Kotlin magic. And scoping magic that I will not explain. By the way, do you any of you guys know Kotlin? I know one guy does. Okay, you people probably know why this works. For the rest, it just works. If you

want me to show you, come to the booth. Um then you can map it into into this. And this um means that if I'd say I I would try to integer into this row, uh on as a as a name, I would get a compilation error, right? A nice red squiggly line that prohibits me from doing that. >> And another cool thing is that I can do

my queries like so, right? I can join tables together, and it automatically knows uh because of my reference here, how to actually join them. Uh and I can do stuff like select all to like do a do a star select. Um I can have a DSL for to map my where clauses, right? To say, "Hey, yeah, my ID needs to be equal to this ID." And you

can do more obviously also more complex stuff. And these are also type safe. And you still have the have the ability to probably understand what this kind of SQL will produce, right? So, there's no hidden magic there. It's just a relatively simple mapper that provides a type safe DSL. >> So, since I use this um I I will use Kotlin and Exposed for the next uh three

as promised. And I want to show a little bit of Javalin. Javalin uh you can use both with Kotlin and with Java. It's also not super young. and I prefer to use it in Kotlin because it offers a nice DSL to do all of the HTTP routing. Which looks like so, right? So, I can I I can create the Javalin server. Uh I configure it to maybe

use virtual dependent on configuration. I also need to configure an object mapper. Um and uh throw it into the the the into the correct like adapter for their JSON for their JSON mapper abstraction. And then I can build my API routes. is important to to look at is that I do not return anything from these functions. Instead, I need to call uh JSON on the context object.

Right? A lot A lot of the uh reactive frameworks, Helidon uh forces you to do the same. And a lot of reactive frameworks have this concept of calling a function on like a context object or on the response object to actually send data instead of returning something. if you know like some Go micro frameworks or some JavaScript micro frameworks like Express JS, this is probably relatively relatively

well known. But it is also a micro framework like Helidon, so you need to set up everything yourself. Right? This is a pattern that continues through most micro frameworks. So I need to also set up a metrics endpoint on my own. I don't get some some Spring Boot or enterprise magic that just works. What makes Javelin especially interesting to me is or maybe it is very interesting

in some cases is it's super low startup time. I also benchmarked a little bit of startup time and after JVM start, Javelin is up on my local machine in less than 100 milliseconds. On like a cloud instance, it took about 100 milliseconds to come up. So and it it won that benchmark by quite a bit. So it's it's very very fast. Next, I want to show HTTP4K

and now I'm entering the realm of Kotlin only micro frameworks. HTTP4K is [snorts] very very similar to Javelin. It follows a similar idea to describe server and routing as functions. And it is therefore also good in some of the same scenarios as Javelin is. So low But what makes what makes HTTP4K very interesting and more so than Javelin to me is that you can swap out the

underlying server implementation freely. So, it has all of the integrations you would expect like Jetty, Netty, like all those servlet containers, Tomcat. but you can also run it on a Helidon or on Undertow or on Ktor if you so wish. you can even integrate it into Spring So, you can start your Spring Boot application and then some part of it is you can hand off to uh

to HTTP 4K. I don't know why one would do that, but it is possible and easy. >> And uh this is what it looks like. You can probably see it's somewhat similar to to Javelin when it comes to the DSL. It just leans a lot more into the brevity that Kotlin um provides. Right? So, I have things like get and then I don't even have a dot

in between for in between function calls anymore. Uh and a lot of lambdas. But, as it's a micro uh as it's a micro uh framework, I need to also like configure some JSON stuff in this case in in HTTP 4K's. Um in HTTP 4K's case, well, that's a tongue twister. Um JSON mapping is done through so-called lenses, which are essentially just a cached mapper. Cached object mapper.

yeah, and I also need to set up the the metrics myself. Um and then I can when I want to return something back to my client, here I actually return a response object. And then I can I can um syntax right here, this visit DTO lens of visit DTO will actually cause it to produce JSON. Now, I have one final framework which I want to show you,

which is Ktor by JetBrains. So, this is the JetBrains red pill, right? You can't do more JetBrains than this. Ktor is interesting since it is on the one hand multi-platform framework through Kotlin multi-platform. So, you can cross-compile it to be native uh without GraalVM. So, it will produce a single executable. The problem with doing that is mainly that you are then are not able to use most

of the most of what the JVM ecosystem um provides you with. So, no option to use the Hikari connection pool or Flyway or whatever. So, it is possible theoretically, but the use case is very limited in my opinion. But, you can also very because it doesn't really rely on reflection at all, uh it is super easy to use with GraalVM as well. If you want to produce

native binaries. And what also makes it a little bit different is that it uses structured concurrency through Kotlin's coroutines. little bit interesting um as a look as as kind of something to look out for in Java in the future when structured concurrency comes. It is a little bit different than what Kotlin is doing, but it might enable similar concepts to come to Java. since this is um

Kotlin coroutines and coroutines in Kotlin rely on function coloring. It is a little really like the queries look a little bit different. The methods are now are now colored with the suspend keyword and they are also not using normal transactions anymore but suspending transactions. And that's the only difference right there. It also sports a routing DSL relatively similar to Javelin and HTTP/2. So you can define routes

and use your standard HTTP verbs. And to respond and send something back to the client you use call.respond and then whatever is in there. JSON serialization is done through Kotlin X serialization which is relatively similar to what Micronaut is doing with their serializable stuff. does not rely on on Jackson. But their own stuff. Also, never forget this call at the end otherwise your endpoint will just hang

forever until your socket timeouts. It happened to me once. I was very confused. Okay, but what Ktor offers which is missing in the previous three microframeworks Helidon included is sensible plugin API and a bigger plugin ecosystem. So I don't need to set up everything myself again. I have plugins which I can use and which I can configure to um abstract away some default behavior that you probably

want from almost every application. Like endpoint like uh the collection of micrometer metrics with some nice defaults default configured that are Ktor specific and yeah you can just add any micrometer stuff you want. There is also plugin for actuator style endpoints which one can use. There are plugins for Kafka and a lot more and it has been steadily growing. A couple of years ago Ktor did not

have that ecosystem and you were forced to do on your own which tends to be the issue with micro frameworks, right? You you have to do everything yourself. You have maximum control and you can tweak everything exactly to your liking but that takes time, right? So now since Ktor 3 and their new plugin they have a lot of nice stuff. I actually this slide I thought I

removed. Now I want to talk a little bit about the benchmarking added. Disclaimer again, no professional benchmarking. I basically read the tutorial and follow the tutorial and did not do any benchmark tuning, right? The goal is not to actually compare the maximum that is possible with these that but it's rather to kind of benchmark or at least benchmark a little bit the out of the box experience

and see how that turns out to be. this is kind of the testing environment I chose. I also tested some Spring Boot stuff for like comparability to what I'm going away from. I have an AKS cluster in Azure with a managed Postgres and then I have a Kubernetes cluster with two node pools, so they the load generator and the applications do not interfere with each other by

running on the same node. And then I'm collecting all of these metrics into Grafana. And now come the two most ugliest slides in the whole presentation because it's just a big table. I'm sorry, I had no idea how to do a better job. But it illustrates a couple of nice points. So the with Panache or slash Hibernate stuff and Spring with JPA as well as Micronut with

JPA it's almost the the exact same result. They are horrible. Like N plus one really you over and it's kind of hard to spot in code review in my opinion when when using Hibernate. You need to actually be aware that this happened because it was just in in my in my testing example, right? It was able to only do about 70 let let's say 80 requests per

second. And that's super slow. It's it's and and the mean latency is very high, right? So I was I was calling the the fetch all endpoint by the way with 100 entries in the database being fetched. you can also see that in the main latency. What makes Quarkus interesting is like I did not do any GraalVM stuff. But you can see it has a little bit little

bit lower CPU consumption and the startup time is significantly faster than the Spring equivalent without any optimizations. So that's nice. Quarkus JDBI because right I'm using handcrafted SQL here is quite a bit faster. Right? It can do more than 2,000 requests per second in my super small unprofessional benchmark. The CPU is reasonable. It is a lot higher because it also handles a lot more requests, so that's

fair. The startup time was even slower. You might ask yourself, why why is it slower? I this is this is Quarkus and this is Quarkus. And the culprit is Hibernate. It's actually not Quarkus itself. Hibernate does a lot of stuff on on startup. It will create proxy objects for all of your entities. that's that's where this relatively big difference in such a small application Micronaut JDBC variation.

Oh, by the way, on the left there are the scenarios. This means like um how many requests were done and the second is with how many concurrent connections. Those were the these applications were hit. So, you can see the Quarkus JDBC JBI stuff, it was able to shrug off 1,000 concurrent connections without any bigger issues. Um my and I only listed like the best scenario for them.

If they broke, I did discard the scenario. Um Micronaut JDBC, uh I must have done something wrong in my testing. I don't know what. I've absolutely no idea. If anyone has time because I don't have enough time to do it, if anyone has time to to look at my code and tell me what the hell I did wrong with Micronaut. I believe there was Was there anyone

using Micronaut? No. Okay, unfortunate. But, I refuse to believe that these are the real numbers. I think that it's a skill issue and I did something stupid in there. But, surprisingly, and it seriously it surprised me a little bit, the winner in my bad performance comparison was Spring with Spring Data JDBC. And it has turned out that Spring Boot 4 with virtual threads turned on is very

resource efficient and surprisingly fast. And there's only a a single of the microframeworks that actually beat Spring Boot's numbers in Right? If you were to look at raw HTTP If you were only testing HTTP and not actually testing um it against the uh with um uh network latency, those numbers would look completely different. Even if you if I'm running this like on my local Docker container, all

of the microframeworks will beat Spring Boot, but in the somewhat real deployment scenario, the difference shrinks a lot because of network latency. Helidon SE was the only one that beat Spring. it did so by not that much. Which is okay. but I was a little bit surprised. I was expecting a little bit more out of Helidon specifically. but I mean, it's fair. The issue is or the

bottleneck in that case is not really the server or the framework itself. The issue is is the database, right? It doesn't It can actually not respond any faster. Um So, but it handled this load very well. So, if you are considering using Helidon for something and you probably have a very high request per second count that you want to handle with minimal resources. And if you are

at that point in time, you will also probably start optimizing your database queries and your database layout and um distributing the load that goes to your database to multiple uh to no to multiple other nodes or do some other optimizations like to do some read replicas or something. Um but yeah, that's it. Uh Javelin, as I said, has the most impressive startup time out of all of

these. Right? It is It It started in in 107 milliseconds, which is super fast. and it performed and all of the other three performed in about the same realm as um uh Quarkus with JDBI. for HTTP/4K, I actually used the Helidon server. So, I was also a little bit surprised to see that, "Hey, why I mean, it is also somewhat reactive. Why is it slower?" And I

had a look at it and profiled it a little bit on my local machine, and it turns out that HTTP/4K is just doing more allocations. It is allocating more meter memory heap memory than uh my application was doing with Helidon SE, and that's where the slowdown is happening. Right? It just does a lot of bit more memory churn. And then Ktor performs very similar to all of

those. So, the question is when should you use what? I'm running very short on time, so I only say like one sentence to Spring Boot 4. Turn on virtual threads. It's free performance. Quarkus is great. I really like it if you do not want to use Spring uh for any reasons. Uh maybe you have an issue with Broadcom and you don't like their licensing model uh or

you prefer to use Jakarta EE, then Quarkus is uh really solid choice. The developer experience is amazing. It's better than Spring's developer experience, and you have and you don't really sacrifice anything when it comes to the amount of integrations that are available. Quarkus, same as Spring, has integrations for everything under the sun. Micronaut is okay. I personally prefer Quarkus over it. And I seem to have some

skill issue with it because my benchmarking numbers seem so off. Um Helidon is interesting. I personally just like the concept of the server. I have not enjoyed my time with MP at all, and SE is okay. Um I would still probably not use it though, unless I really had a very specific scenario of having to handle a lot of incoming requests. And I want and I need

to squeeze out the very last um the very last bit of performance. Yeah, it's it's okay. It's not great. Uh it is the most cumbersome of the micro frameworks I tried. So, even Javelin with Java is a lot more comfortable than than using Helidon SE. Yes, Javelin is probably interesting in like some some serverless scenarios, right? Who if if it has such a low startup time and

with technologies like Crack or the Java AOT cache, you can optimize the JVM startup time uh as well as even your your application startup time a little bit. So, or I think the AWS one is called SnapStart, right? They also have that thing. So, it might be interesting for serverless. And I also like this this very functional approach of server as a function, but I also enjoy

functional programming, which is not for everyone. Um HTTP/4K is fine uh if you are a Kotlin person, and you want this server as just a single function concept, or are working with serverless, and you prefer Kotlin a lot, HTTP/4K might be for you. Um otherwise, it's a little bit niche, in my opinion. And finally, Ktor, uh if you are for some reason tired of the enterprise Java

style, and want to try out something new, or you have team members that are not originally Java developers, and feel uncomfortable with the amount of annotations and classes that are present everywhere in Java, then Ktor might be worth trying out for you. It has also gotten really, really good with the amount of integrations it offers through its plugin API. now is time for questions. And also, if

you want to check out my source code, you can find it here. And because I did this talk uh before, once at Devoxx Belgium last year, one of the um Quarkus team was a little bit angry at because of the performance numbers I I shared. um he wanted to make sure that everyone knows that Quarkus is faster than And he he has created an issue with a

nice link to an to a to a like benchmark uh brings Quarkus to its limits. So, if you want to try that, uh if you want to have a look at at that, and maybe play with it, um you can find it in the Also, if you have questions, uh you can hit me up on LinkedIn, or post an issue there. I will come around to it

and answer you. Um this QR code would lead you to my LinkedIn. A little bit of a of a yeah, sellout as or a little bit of a sell as well. I am organizing organizing a jug in the Euregio region, which is near Aachen, so about an hour from here. We have monthly talks. If you are in the region or if you are considering talking yourself, hit

me up. You can come You are always invited. You can come over. And that is it. Thank you very much. >> [applause]

From event

JCON EUROPE

20 Apr 2026 – 23 Apr 2026

All event videos
Back to Watch