Comparing Top Java/Kotlin Microservice Frameworks: Helidon, Ktor, Micronaut, Quarkus & Spring Boot

This article reviews five Java/Kotlin microservice frameworks—Helidon, Ktor, Micronaut, Quarkus, and Spring Boot—showing how to build heterogeneous services with Consul service discovery, detailing prerequisites, code examples, launch commands, API testing, and a side‑by‑side comparison of their strengths and weaknesses.

Java High-Performance Architecture
Java High-Performance Architecture
Java High-Performance Architecture
Comparing Top Java/Kotlin Microservice Frameworks: Helidon, Ktor, Micronaut, Quarkus & Spring Boot

Introduction

In Java and Kotlin, besides using Spring Boot to create microservices, there are many alternative frameworks.

Frameworks

Name

Developer

Helidon SE

Oracle

Ktor

JetBrains

Micronaut

Object Computing

Quarkus

Red Hat

Spring Boot

Pivotal

Based on these microservice frameworks, five services are created and connected via Consul service discovery, forming a heterogeneous microservice architecture (MSA).

Technology Stack

JDK 13

Kotlin

Gradle (Kotlin DSL)

JUnit 5

Functional API

GET /application-info{?request-to=some-service-name}

GET /application-info/logo

Implementation Approach

Configuration via text files

Dependency injection

HTTP API

MSA Details

Service discovery using Consul (register and client‑side load balancing)

Build an uber‑JAR for each service

Prerequisites

JDK 13

Consul

Creating Applications

Generate new projects from any of the frameworks using a web starter, build tool, or IDE.

Helidon Service

Helidon offers two versions: SE and MicroProfile (MP). Both run as regular Java SE programs. Helidon MP implements Eclipse MicroProfile APIs; Helidon SE follows a "no magic" approach with minimal annotations.

Helidon SE is used for the microservice; Koin provides dependency injection.

object HelidonServiceApplication : KoinComponent {<br/>    @JvmStatic<br/>    fun main(args: Array<String>) {<br/>        val startTime = System.currentTimeMillis()<br/>        startKoin { modules(koinModule) }<br/>        val applicationInfoService: ApplicationInfoService by inject()<br/>        val consulClient: Consul by inject()<br/>        val applicationInfoProperties: ApplicationInfoProperties by inject()<br/>        val serviceName = applicationInfoProperties.name<br/>        startServer(applicationInfoService, consulClient, serviceName, startTime)<br/>    }<br/>}<br/><br/>fun startServer(<br/>    applicationInfoService: ApplicationInfoService,<br/>    consulClient: Consul,<br/>    serviceName: String,<br/>    startTime: Long<br/>): WebServer {<br/>    val serverConfig = ServerConfiguration.create(Config.create().get("webserver"))<br/>    val server: WebServer = WebServer.builder(createRouting(applicationInfoService))<br/>        .config(serverConfig)<br/>        .build()<br/>    server.start().thenAccept { ws -><br/>        val durationInMillis = System.currentTimeMillis() - startTime<br/>        log.info("Startup completed in $durationInMillis ms. Service running at: http://localhost:" + ws.port())<br/>        consulClient.agentClient().register(createConsulRegistration(serviceName, ws.port()))<br/>    }<br/>    return server<br/>}<br/>

Routing configuration:

private fun createRouting(applicationInfoService: ApplicationInfoService) = Routing.builder()<br/>    .register(JacksonSupport.create())<br/>    .get("/application-info") { req, res -><br/>        val requestTo = req.queryParams().first("request-to").orElse(null)<br/>        res.status(Http.ResponseStatus.create(200)).send(applicationInfoService.get(requestTo))<br/>    }<br/>    .get("/application-info/logo") { req, res -><br/>        res.headers().contentType(MediaType.create("image", "png"))<br/>            .status(Http.ResponseStatus.create(200)).send(applicationInfoService.getLogo())<br/>    }<br/>    .error(Exception::class.java) { req, res, ex -><br/>        log.error("Exception:", ex)<br/>        res.status(Http.Status.INTERNAL_SERVER_ERROR_500).send()<br/>    }<br/>    .build()<br/>

Configuration (HOCON):

webserver {<br/>  port: 8081<br/>}<br/>application-info {<br/>  name: "helidon-service"<br/>  framework {<br/>    name: "Helidon SE"<br/>    release-year: 2019<br/>  }<br/>}<br/>

Ktor Service

Ktor is designed for Kotlin. Like Helidon SE, it lacks built‑in DI, so Koin is used before starting the server.

val koinModule = module {<br/>    single { ApplicationInfoService(get(), get()) }<br/>    single { ApplicationInfoProperties() }<br/>    single { ServiceClient(get()) }<br/>    single { Consul.builder().withUrl("https://localhost:8500").build() }<br/>}<br/><br/>fun main(args: Array<String>) {<br/>    startKoin { modules(koinModule) }<br/>    val server = embeddedServer(Netty, commandLineEnvironment(args))<br/>    server.start(wait = true)<br/>}<br/>

Ktor configuration (HOCON):

ktor {<br/>  deployment {<br/>    host = localhost<br/>    port = 8082<br/>    environment = prod<br/>    autoreload = true<br/>    watch = [io.heterogeneousmicroservices.ktorservice]<br/>  }<br/>  application {<br/>    modules = [io.heterogeneousmicroservices.ktorservice.module.KtorServiceApplicationModuleKt.module]<br/>  }<br/>}<br/><br/>application-info {<br/>  name: "ktor-service"<br/>  framework {<br/>    name: "Ktor"<br/>    release-year: 2018<br/>  }<br/>}<br/>

Ktor module definition:

fun Application.module() {<br/>    val applicationInfoService: ApplicationInfoService by inject()<br/>    if (!isTest()) {<br/>        val consulClient: Consul by inject()<br/>        registerInConsul(applicationInfoService.get(null).name, consulClient)<br/>    }<br/>    install(DefaultHeaders)<br/>    install(Compression)<br/>    install(CallLogging)<br/>    install(ContentNegotiation) { jackson {} }<br/>    routing {<br/>        route("application-info") {<br/>            get {<br/>                val requestTo = call.parameters["request-to"]<br/>                call.respond(applicationInfoService.get(requestTo))<br/>            }<br/>            static { resource("/logo", "logo.png") }<br/>        }<br/>    }<br/>}<br/>

Micronaut Service

Micronaut, created by the Grails authors, supports Java, Kotlin, and Groovy with compile‑time DI, resulting in lower memory usage and faster startup.

object MicronautServiceApplication {<br/>    @JvmStatic<br/>    fun main(args: Array<String>) {<br/>        Micronaut.build()<br/>            .packages("io.heterogeneousmicroservices.micronautservice")<br/>            .mainClass(MicronautServiceApplication.javaClass)<br/>            .start()<br/>    }<br/>}<br/>

Controller example:

@Controller(value = "/application-info", consumes = [MediaType.APPLICATION_JSON], produces = [MediaType.APPLICATION_JSON])<br/>class ApplicationInfoController(private val applicationInfoService: ApplicationInfoService) {<br/>    @Get fun get(requestTo: String?): ApplicationInfo = applicationInfoService.get(requestTo)<br/>    @Get("/logo", produces = [MediaType.IMAGE_PNG]) fun getLogo(): ByteArray = applicationInfoService.getLogo()<br/>}<br/>

Micronaut configuration (YAML):

micronaut:<br/>  application:<br/>    name: micronaut-service<br/>  server:<br/>    port: 8083<br/><br/>consul:<br/>  client:<br/>    registration:<br/>      enabled: true<br/><br/>application-info:<br/>  name: ${micronaut.application.name}<br/>  framework:<br/>    name: Micronaut<br/>    release-year: 2018<br/>

Quarkus Service

Quarkus targets cloud‑native environments with low memory consumption and fast startup, offering live reload out of the box.

@Path("/application-info")<br/>@Produces(MediaType.APPLICATION_JSON)<br/>@Consumes(MediaType.APPLICATION_JSON)<br/>class ApplicationInfoResource(@Inject private val applicationInfoService: ApplicationInfoService) {<br/>    @GET fun get(@QueryParam("request-to") requestTo: String?): Response =<br/>        Response.ok(applicationInfoService.get(requestTo)).build()<br/>    @GET @Path("/logo") @Produces("image/png") fun logo(): Response =<br/>        Response.ok(applicationInfoService.getLogo()).build()<br/>}<br/>

Consul registration bean:

@ApplicationScoped<br/>class ConsulRegistrationBean(@Inject private val consulClient: ConsulClient) {<br/>    fun onStart(@Observes event: StartupEvent) { consulClient.register() }<br/>}<br/>

Spring Boot Service

Spring Boot simplifies development through auto‑configuration and the Spring ecosystem.

@RestController<br/>@RequestMapping(path = ["application-info"], produces = [MediaType.APPLICATION_JSON_VALUE])<br/>class ApplicationInfoController(private val applicationInfoService: ApplicationInfoService) {<br/>    @GetMapping fun get(@RequestParam("request-to") requestTo: String?): ApplicationInfo = applicationInfoService.get(requestTo)<br/>    @GetMapping(path = ["/logo"], produces = [MediaType.IMAGE_PNG_VALUE]) fun getLogo(): ByteArray = applicationInfoService.getLogo()<br/>}<br/>

Spring Boot configuration (YAML):

spring:<br/>  application:<br/>    name: spring-boot-service<br/>server:<br/>  port: 8085<br/>application-info:<br/>  name: ${spring.application.name}<br/>  framework:<br/>    name: Spring Boot<br/>    release-year: 2014<br/>

Starting Services

Before starting services, install Consul and run a dev agent (e.g., consul agent -dev).

Launch each service with the following commands:

java -jar helidon-service/build/libs/helidon-service-all.jar<br/>java -jar ktor-service/build/libs/ktor-service-all.jar<br/>java -jar micronaut-service/build/libs/micronaut-service-all.jar<br/>java -jar quarkus-service/build/quarkus-service-1.0.0-runner.jar<br/>java -jar spring-boot-service/build/libs/spring-boot-service.jar<br/>

After all services are running, visit http://localhost:8500/ui/dc1/services to view them.

API Testing

Example responses from the Helidon service:

{<br/>  "name": "helidon-service",<br/>  "framework": {"name": "Helidon SE", "releaseYear": 2019},<br/>  "requestedService": null<br/>}<br/>
{<br/>  "name": "helidon-service",<br/>  "framework": {"name": "Helidon SE", "releaseYear": 2019},<br/>  "requestedService": {<br/>    "name": "ktor-service",<br/>    "framework": {"name": "Ktor", "releaseYear": 2018},<br/>    "requestedService": null<br/>  }<br/>}<br/>

Tools such as Postman, IntelliJ IDEA HTTP client, or a browser can be used for testing.

Framework Comparison

Helidon SE

Pros: Application requires only a single annotation (@JvmStatic).

Cons: Some components (e.g., DI, service‑discovery integration) are not provided out of the box.

Helidon MP

Implements Eclipse MicroProfile, giving access to Java EE APIs and MicroProfile extensions.

Ktor

Pros: Lightweight; you add only the features you need.

Cons: Tied to Kotlin; fewer experts available; more configuration required compared to Spring Boot.

Micronaut

Pros: AOT compilation reduces startup time and memory usage; familiar to Spring developers.

Quarkus

Pros: Implements Eclipse MicroProfile; provides compatibility layers for Spring APIs (DI, Web, Security, Data JPA).

Spring Boot

Pros: Mature ecosystem, extensive documentation, and a large pool of experts; starters and auto‑configuration simplify development.

Cons: Many configuration parameters can make the application heavy; however, they can be trimmed with careful tuning.

Conclusion

All examined frameworks can deliver a simple HTTP API service that participates in a heterogeneous microservice architecture. Choosing the right one depends on trade‑offs such as startup time, memory footprint, ecosystem maturity, and developer familiarity.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaMicroservicesKotlinframework comparison
Java High-Performance Architecture
Written by

Java High-Performance Architecture

Sharing Java development articles and resources, including SSM architecture and the Spring ecosystem (Spring Boot, Spring Cloud, MyBatis, Dubbo, Docker), Zookeeper, Redis, architecture design, microservices, message queues, Git, etc.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.