<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: netfishx</title>
    <description>The latest articles on Forem by netfishx (@netfishx).</description>
    <link>https://forem.com/netfishx</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1424867%2Ff373fe83-756a-4e2c-8ea1-445b19005990.jpeg</url>
      <title>Forem: netfishx</title>
      <link>https://forem.com/netfishx</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/netfishx"/>
    <language>en</language>
    <item>
      <title>Same API in Java, Go, Rust, and Kotlin — a 4-language benchmark</title>
      <dc:creator>netfishx</dc:creator>
      <pubDate>Thu, 19 Mar 2026 05:35:29 +0000</pubDate>
      <link>https://forem.com/netfishx/same-api-in-java-go-rust-and-kotlin-a-4-language-benchmark-2fn6</link>
      <guid>https://forem.com/netfishx/same-api-in-java-go-rust-and-kotlin-a-4-language-benchmark-2fn6</guid>
      <description>&lt;p&gt;After 21 years of Java development, I rebuilt our short-video platform backend in Go, Rust, and Kotlin (Ktor) to make an informed decision about our production stack. Same API across all four: authentication, video feed, follow system, S3 uploads, Redis caching. Here are the results.&lt;/p&gt;

&lt;h2&gt;
  
  
  Performance summary
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Throughput&lt;/strong&gt; (wrk, 200 concurrent, 10s, health endpoint)&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Java&lt;/th&gt;
&lt;th&gt;Go&lt;/th&gt;
&lt;th&gt;Rust&lt;/th&gt;
&lt;th&gt;Kotlin&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;QPS&lt;/td&gt;
&lt;td&gt;88K&lt;/td&gt;
&lt;td&gt;100K&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;210K&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;99K&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Latency distribution&lt;/strong&gt; (200 concurrent)&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Go&lt;/th&gt;
&lt;th&gt;Rust&lt;/th&gt;
&lt;th&gt;Kotlin&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;p50&lt;/td&gt;
&lt;td&gt;1.79 ms&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.70 ms&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1.60 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;p99&lt;/td&gt;
&lt;td&gt;6.13 ms&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1.48 ms&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;15.36 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Memory under 500 concurrent connections (RSS)&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Java&lt;/th&gt;
&lt;th&gt;Go&lt;/th&gt;
&lt;th&gt;Rust&lt;/th&gt;
&lt;th&gt;Kotlin&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Peak&lt;/td&gt;
&lt;td&gt;372 MB&lt;/td&gt;
&lt;td&gt;60 MB&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;33 MB&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;650 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Cold start&lt;/strong&gt; (binary to first HTTP response)&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Java&lt;/th&gt;
&lt;th&gt;Go&lt;/th&gt;
&lt;th&gt;Rust&lt;/th&gt;
&lt;th&gt;Kotlin&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Time&lt;/td&gt;
&lt;td&gt;2,714 ms&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;69 ms&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;153 ms&lt;/td&gt;
&lt;td&gt;914 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Build time&lt;/strong&gt; (clean, deps cached)&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Java&lt;/th&gt;
&lt;th&gt;Go&lt;/th&gt;
&lt;th&gt;Rust&lt;/th&gt;
&lt;th&gt;Kotlin&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Time&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;5.6s&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;9.4s&lt;/td&gt;
&lt;td&gt;98.3s&lt;/td&gt;
&lt;td&gt;14.1s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Things that surprised me
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Kotlin nearly matches Go in throughput.&lt;/strong&gt; Ktor 3.4 + Netty + JVM 21 Virtual Threads hit 99K QPS — within 1% of Go's 100K. JIT optimization on hot paths is real. But p99 latency (15ms) and memory (650 MB) remind you it's JVM under the hood.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rust memory usage barely changes under load.&lt;/strong&gt; 19 MB idle → 33 MB at 500 concurrent. No GC means no memory spikes from GC heap expansion. Go went from 25 to 60 MB, which is still excellent.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Go has the fastest cold start, not Rust.&lt;/strong&gt; I assumed compiled-to-native would be roughly equal, but Go at 69ms vs Rust at 153ms. Tokio runtime initialization (thread pool, epoll) adds overhead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rust has the fewest lines of code.&lt;/strong&gt; 4,179 lines in 37 files. Go was 4,929 (hand-written), Java 7,001, Kotlin 8,607 (includes tests). Rust's type system and enum/match expressiveness reduce boilerplate significantly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The hardest part wasn't writing Rust — it was getting Kotlin to build.&lt;/strong&gt; Gradle plugin compatibility issues consumed more time than both the Go and Rust implementations combined. In 2026, starting a new JVM project from scratch still feels unnecessarily painful.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I actually chose
&lt;/h2&gt;

&lt;p&gt;Rust (Axum) for production. The deciding factor was infrastructure cost: roughly half the memory means half the EC2 instances. The compile time penalty (~98s clean) is mitigated with BuildKit cache mounts in CI.&lt;/p&gt;

&lt;p&gt;But I wouldn't universally recommend Rust. Here's my honest take:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Need to ship fast with a team?&lt;/strong&gt; Go. 9s builds, 69ms cold start, anyone can be productive in a week.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Already invested in JVM but want modern?&lt;/strong&gt; Kotlin + Ktor. Competitive throughput, 3x faster startup than Spring, great language ergonomics.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance-critical core services, willing to invest?&lt;/strong&gt; Rust. The numbers speak for themselves, but the learning curve and compile times are real costs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enterprise ecosystem dependency?&lt;/strong&gt; Java/Spring isn't going anywhere, but the performance gap is widening.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Methodology and caveats
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Single machine: macOS Apple Silicon, Docker (OrbStack)&lt;/li&gt;
&lt;li&gt;DB: PostgreSQL 18 (Go/Rust/Kotlin), MySQL 8.4 (Java only — not ideal)&lt;/li&gt;
&lt;li&gt;Benchmark: health endpoint only (no DB queries), wrk 4 threads&lt;/li&gt;
&lt;li&gt;Java implementation has different API paths and wasn't fully feature-equivalent&lt;/li&gt;
&lt;li&gt;No GraalVM native-image tested (would improve Java/Kotlin startup and memory)&lt;/li&gt;
&lt;li&gt;Kotlin JIT may not have been fully warmed up&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Happy to answer questions or share specific details about any of the implementations.&lt;/p&gt;

</description>
      <category>go</category>
      <category>rust</category>
      <category>kotlin</category>
      <category>java</category>
    </item>
  </channel>
</rss>
