Learning

Go or Rust: deciding which to commit to

November 12, 2026

This note is a decision overview for picking a second language next to Java. The Java side of the comparison is the outline in what modern Java looks like. The work it is written against is the work on the work page: Java services, Jakarta EE, Spring Boot, payments, and bank interfaces. Nothing here is a record of having shipped Go or Rust in production. The Go that already runs on this site is a separate reading note, the camt and pain readers.

The conclusion is blank on purpose. The last section is a checklist, and the lines marked TODO are where my own decision goes once I have done the looking.

Learning curve, coming from Java

Go is a small language with a garbage collector. A Java developer already knows the shape of it: packages, functions, structs, interfaces, loops, and values passed around. The surprises are local. Names that start with a capital letter are public. Errors are returned, not thrown. There is no inheritance of implementation. Interfaces are satisfied by having the methods, with no implements clause. The compiler is fast, and gofmt leaves one layout.

Rust is a different kind of step. Ownership, borrowing, and lifetimes are the language, not a library. The compiler rejects programs a Java compiler would accept, because the Java program would rely on the garbage collector and on the programmer to avoid use-after-free and data races. Reading Rust gets easier before writing it does. Writing it well is the long part.

TODO: after a short exercise in each, write which of those surprises actually slowed me down. Keep it to what I hit, not to a general claim about either language.

Concurrency

Go's unit of concurrency is the goroutine: a function the runtime schedules onto operating-system threads. Goroutines are cheap enough that a server can use one per request and write blocking code. Channels move values between them. select waits on more than one. Sharing memory with a mutex is also ordinary Go. The feel is close to the pitch of Java virtual threads — blocking code, many threads — with channels as an extra primitive. The comparison with virtual threads belongs next to the Java note once that section is filled in.

Rust has threads and mutexes too. The type system tracks Send and Sync, so sharing across threads is a type error when it is unsafe. The usual way to write a network service is async/await on a runtime such as Tokio. That is a different model from goroutines. Suspension points are marked in the code, and the types of the futures can dominate the signature. There is no garbage collector pausing the process, and there is also no runtime that makes a blocking call inside an async function cheap or correct.

TODO: one paragraph in my own words on which model I can hold in my head while reading someone else's code. Goroutines and channels, or async Rust. Write it after reading a real example of each, and link the example.

Memory

Go is garbage collected. The compiler decides whether a value stays on the stack or escapes to the heap. Pointers exist. The programmer does not free memory.

Rust gives each value an owner. A borrow is a reference with a lifetime, and the compiler checks that the reference does not outlive the value. There is no garbage collector. The cost shows up in the types (String versus &str, Vec versus a slice, Box, Rc, Arc) rather than in a collector.

For service code that spends its time on I/O and JSON, the collector is rarely the thing a Java developer is trying to escape. For a parser or a component on a latency budget, the collector is the thing Rust is for.

TODO: say which of those two sentences matches the work I want to be hired for. Leave it empty until the checklist below has an answer.

Tooling and ecosystem

Go ships as the go command: modules, go test, go fmt, and a standard library that covers HTTP, JSON, and concurrency. A program builds to one static binary. The camt and pain readers on this site are that shape: a go.mod, the standard encoding/xml and encoding/json packages, and one third-party module for the Netlify function signature.

Rust ships as rustup and Cargo. Dependencies come from crates.io. rustfmt and Clippy are the usual format and lint tools. Compiler errors are specific. Compile times are longer than Go's, and the ecosystem is large, with more choice of crates for the same job.

TODO: note the first library I had to go looking for in each language, and whether the standard library would have done it.

Where the languages turn up

These are the domains I am weighing, in the terms of the work rather than as a ranking.

Cloud-native and Kubernetes tooling, including OpenShift, is largely Go. Kubernetes itself, the Docker engine, containerd, Terraform, and Prometheus are Go codebases. A controller written with Kubebuilder is Go. OpenShift is a Kubernetes distribution, so the same applies to a lot of the platform tooling around it. The Strimzi operator, which the Kafka note is about, is a Java project (strimzi-kafka-operator). Reading that operator is Java work.

Microservices in the style of a Spring Boot service — HTTP, JSON, a database or a queue — are a short step in Go: one binary, a garbage collector, blocking handlers or goroutines. The same service can be written in Rust. The distance from Spring is larger, because the memory model and the async runtime come along with the HTTP stack.

CLIs are a natural Go program, for the same reason: a static binary and a fast edit-compile cycle. Rust is also a common CLI language. The difference I care about at the start is how long it takes to get the first useful version, not the ceiling.

Systems and performance-critical code is Rust's case. The language is built to express ownership of memory and to exclude data races. Go runs plenty of demanding infrastructure and accepts garbage collection as the trade. I want the later comparison with virtual threads to stay honest about that trade, once the Java note has the Loom section filled in.

WebAssembly is a first-class Rust target, used for code that runs in the browser and in some edge runtimes. Go can compile to WebAssembly. The output includes the Go runtime, so a small module is a less usual reason to pick Go.

TODO: mark which of these domains I actually want the second language for. One of them, not all of them.

Kafka, streaming, and fintech

The Java client that ships with Apache Kafka is the client a Spring service already has a path to. Go has clients in wide use, among them kafka-go and confluent-kafka-go. Rust has rdkafka, which wraps librdkafka. This note does not pick one.

On the banking side, the work described on this site is Java: interfaces, FinTS, file and batch integration, Camunda in an earlier role. Neither Go nor Rust replaces that for the application itself. Go is already how this site reads a camt.053 statement and a pain.001 payment: a small program, XML in, JSON out, deployed as a function. That is a payments-shaped task of the kind Go is comfortable for, and a task a Rust parser would also suit. It is one data point about a fit, and it is written up on its own.

TODO: if a streaming example is the practice project, write down which client I used and what broke. Do not turn this section into a claim that one language is the fintech language.

Job-market signals

Qualitatively, from the shape of the work rather than from a survey table:

Java is still the language the core-banking and payments application roles are written in. A second language adds listings. It does not retire the first one.

Go is the second language that shows up beside Kubernetes, platform, and cloud-native service roles. That follows from where the tooling is written, above, more than from a hiring statistic.

Rust shows up on a narrower set of roles: systems, security-sensitive components, and infrastructure where the memory model is the requirement. Fewer banking application posts ask for it. The posts that do are more specific.

The Stack Overflow Developer Survey publishes language rankings each year. This note deliberately does not copy a percentage, a salary figure, or a "most loved" rank out of it. Those numbers go stale, and a pasted figure with no table under it is worse than none. Read the current edition, and read current listings.

TODO: look at current listings for the kind of role I would actually take in Berlin. Write what the posts asked for, with links to the posts. If a number ends up in this note, it comes from one of those pages and the link stays next to it.

A checklist, and then my conclusion

Answer these in order. The decision is the last line, and it is empty until then.

  1. Name the work the second language is for: platform and Kubernetes tooling, service backends beside Java, or systems and performance-critical code. One primary.
  2. Do the small version of the program this site already has: read a file, return JSON. Once in Go, once in Rust. Write down which one I was willing to finish, and where I got stuck. The Go version can start from the readers already in this repo.
  3. Read one codebase I did not write. A Kubernetes controller in Go, and a small Rust program of similar length. Note which reading was usable on a weekday evening.
  4. Read current Berlin listings and the current Stack Overflow survey. Link them. Count nothing in this note that I cannot point at.
  5. Decide whether the Kafka-on-OpenShift study needs either language. The Strimzi operator is Java, and the first Kafka client in a Spring service is the Java client. A second language can still be the right use of the time. It is a separate question from finishing that note.
  6. Write the conclusion in one paragraph: which language I will commit practice time to, for how long, and what I will ship with it. The other language stays available. This note is about the commitment, not about a ban.

TODO: my conclusion, after the checklist. One paragraph. Leave the paragraph out rather than guess it.

Read as a checklist with the conclusion still empty, Go is the shorter step from Java into Kubernetes-side and service work, and it is the language already running on this site. Rust is the longer step, and the one that matters if the target work is ownership and the absence of a garbage collector. Neither replaces Java for the core banking work on the work page. That leaning is a summary of the sections above. It is not the decision in item 6.

All notes