Migrating from Go to Rust

409 points - yesterday at 6:31 PM

Source

Comments

Animats yesterday at 9:07 PM
I could see migrating from C or C++ or Python to Rust, for various reasons, but for web back-end work Go is a good match. I write almost entirely in Rust, but the last time I had to do something web server side in Rust, I now wish I'd used Go.

The OP points out the wordyness of Go's error syntax. That's a good point. Rust started with the same problem, and added the "?" syntax, which just does a return with an error value on errors. Most Go error handling is exactly that, written out. Rust lacks a uniform error type. Rust has three main error systems (io::Error, thiserror, and anyhow), which is a pain when you have to pass them upward through a chain of calls.

(There are a number of things which tend to be left out of new languages and are a pain to retrofit, because there will be nearly identical but incompatible versions. Constant types. Boolean types. Error types. Multidimensional array types. Vector and matrix types of size 2, 3, and 4 with their usual operations. If those are not standardized early, programs will spend much time fussing with multiple representations of the same thing. Except for error handling, these issues do not affect web dev much, but they are a huge pain for numerical work, graphics, and modeling, where standard operations are applied to arrays of numbers.)

Go has two main advantages for web services. First, goroutines, as the OP points out. Second, libraries, which the OP doesn't mention much. Go has libraries for most of the things a web service might need, and they are the ones Google uses internally. So they've survived in very heavily used environments. Even the obscure cases are heavily used. This is not true of Rust's crates, which are less mature and often don't have formal QA support.

tptacek yesterday at 10:10 PM
This is a weird document that is simultaneously trying to serve as a migration guide and an advocacy document for Rust.

Ultimately, if you have to ask, the Rust vs. Go consideration boils down almost completely to "do you want a managed runtime or not". A generation of Rust programmers has convinced itself that "managed runtime" is bad, that not having one is an important feature. But that's obviously false: there are more programming domains where you want a managed runtime than ones where you don't.

That's not an argument for defaulting to Go in all those cases! There are plenty of subjective reasons to prefer Rust. I miss `match` when I write Go (I do not miss tokio and async Rust, though). They're both perfectly legitimate choices in virtually any case where you don't have to distort the problem space to fit them in (ie: trying to write a Go LKM would be a weird move).

The Rust vs. Go slapfight is a weird and cringe backwater of our field. Huge portions of the industry are happily building entire systems in Python or Node, and smirking at the weirdos arguing over which statically typed compiled language to use. Python vs. (Rust|Go) is a real question. Rust vs. Go isn't.

amusingimpala75 yesterday at 8:56 PM
This is probably going to sound generic / repetitive, but my biggest complaint about Rust is the package management situation, which is entirely the result of the developer mindset. I love the ergonomics on the rust side (the functional approach to data types is beautiful), but I’m working on two projects side by side, one in rust and one in go at the moment. The dependency trees are entirely different beasts, with most of the stuff on the go project covered by the stdlib whereas I think the rust project is over 400 despite asking for just rusqlite (sqlite), clap (cli), ratatui (tui), and tauri (gui), the last of which is by far the worst offender but even without it, it’s still close on 100 which is crazy. If there were (and maybe there are, I just haven’t found them) decently maintained alternatives to the rust crates that actually have a sane dependency approach, I’d feel much better. I’m just trying to not shai hulud my system, and the rust-web people seem to want to turn cargo into npm in that regard.
nemo1618 yesterday at 9:20 PM
LLM writing tells are getting more subtle, but they still jump off the page for me, in particular the word "genuine:"

   "This is the area where Go genuinely shines, and it’s worth being precise about why"
   "the lack of GC pauses is a genuine selling point"
   "Humans are genuinely bad at reasoning about memory"
   "There are cases where the borrow checker is genuinely too strict"
tbc I don't think the article was fully AI-generated, just AI-assisted. If so, the author did a genuinely good job of it! No one else is commenting on it, so clearly it didn't detract much from the substance. It's just weird that this is becoming increasingly common, and increasingly hard to detect.
cbondurant yesterday at 10:08 PM
I already use Rust and don't have experience with Go, so this article maybe isn't super for me.

I do have one nitpick though: Stating that data races are "caught at compile time" in Rust feels like it is overstating the case, at least a little. It sounds a bit like its implying Rust can also handle things like mutual lock starvation, or other concurrency issues. When that's simply not the case. I know "data race" is technically a formal term, with a decently narrow scope, yet I still think it could be a bit clearer about it.

rr808 today at 3:05 PM
One reason I like Go is the fast compile. Rust really slows you down. Esp in days of AI when agents are building/testing in cycles.
geenat yesterday at 9:10 PM
If verbosity is a main stickler, this is coming to golang 1.28 which will cut it down drastically:

https://github.com/golang/go/issues/12854#issue-110104883

kayo_20211030 yesterday at 9:09 PM
If you have a green field, by all means write it in rust. If you have a brown field, and a functional profitable system, rewrite the parts that need rewriting in the original language, whatever that is, and carry on. Make your systems better in small measurable ways, with the language you know and a team you trust to implement it all. Anything else is a wasteful religious argument.
cliftonk today at 5:34 PM
I have preferred rust for many years now, but we’ll be using models spitting out 500-1500 or more tokens/sec soon and rust compile times are glacially slow (while go is almost instantaneous).
apatheticonion today at 1:28 PM
I wrote Go professionally for years. Moved to Rust and couldn't be happier. There are some annoying syntax quirks but they are minor.

After writing web services, GUI apps and terminal apps professionally in Rust, I honestly struggle to see a use case for other languages.

mxey today at 3:12 PM
> You literally cannot dereference an Option without acknowledging the None case. Whole categories of pager-duty incidents disappear.

This is at the very least misleading, given that you can use unwrap.

Regarding error handling: will a parser error in the config return an error that includes the name of the file that’s failed to parse? That’s the kind of useful context that I add to errors in Go.

gertlabs yesterday at 8:59 PM
I liked Rust before running a benchmark, but the gap between how effectively most LLMs write in Rust vs Go was still surprisingly large to me (especially in agentic harnesses where they can fix the initial environment issues). I've become a pretty big Rust evangelist after seeing that. We've had a lot of success writing batch processing tools in Rust to be called by our existing codebase, but haven't attempted a full production migration... yet.

I will say that many of the issues with Go in the article, especially re: nil handling are increasingly solved by thorough coding reviews with Codex. Better to not have the issue in the first place, sure, but these kinds of security bugs are becoming optional to developers who put in at least as much effort to review and understand code as they put into the initial design and execution.

Language data at https://gertlabs.com/rankings?mode=agentic_coding

drykiss today at 2:16 PM
Quite new to Go, so sorry in advance for a stupid question:

> "Go got generics in 1.18 (March 2022), thirteen years after the language shipped. They are useful, but they feel tacked on, and in practice they have most of the downsides of a generic type system without delivering the upsides you’d expect coming from Rust, Haskell, or even modern C++."

The problems with Go generics have now largely been solved, haven't they? Is this comment from the author still applicable?

sgt today at 9:27 AM
Meanwhile.. Java's still around. Modern, and fits the LLM paradigm quite well. It's not going to be as amazing or fast as Rust is, but close.
sg1apm today at 5:28 PM
Curious about the operational side: did the migration affect your deployment pipeline complexity significantly? We recently rewrote a monitoring dashboard from Python/Qt to Go specifically to get a self-contained binary with no runtime dependencies — the deployment story for Go is hard to beat for internal tooling even if Rust would win on performance.
Luker88 today at 9:08 AM
I write purely Go at $dayjob, but I write purely Rust in my projects.

I have a huge list of things that I have in Rust that I would like in Go, but I don't have a single thing I am missing from Go in Rust.

I grow tired of golang "dumb it down" approach as I find it actually just shifts more and more work onto me.

Is anyone in a different position? What does Go have that rust does not?

hebetude today at 2:26 AM
Not sure the article is … accurate? Go has a large standard library. Rust leans on third party cargo libraries which fall into the supply chain attack and has a small standard library. Anyways, that feels immediately biased in the article. Also 11% use Rust? I don’t see that penetration in real long term products. Sure lots of tui apps these days but not things that you can make money working on.
Thaxll yesterday at 9:08 PM
"services that your organization relies on, that have high uptime requirements, that are critical to your business"

Kind of funny when your Rust service runs on Kubernetes.

deleted today at 3:06 PM
jafffsuds today at 2:31 PM
> There’s no built-in goroutine-style preemption. Long CPU-bound work in an async task starves the executor; you offload to tokio::task::spawn_blocking or rayon instead.

I don't know why anyone uses spawn_blocking for CPU-bound tasks. It's clearly designed for blocking IO tasks. There's a reason why Erlang cordons them separately into Dirty CPU and Dirty IO schedulers.

yamapikarya today at 2:25 PM
i like go because it's simple and just works. i like the error handling, if err != nil return err, i like the philosophy to focus using stdlib instead choose which libraries are the best for doing x. i like how go handle the concurrency like using channel or sync.waitgroup. i am very biased but someday i will also learn rust
arjie yesterday at 9:09 PM
I do like using Rust quite a bit, but the presence of arbitrary build-time code in build.rs is very risky until we get better at implementing dev-time sandboxing.
arccy yesterday at 9:07 PM
perhaps the oncall is better if you write your own services, but as an SRE / ops person who has to run other people's services, rust ones just generally seem to be worse: logs that are so verbose but seem to tell you nothing, statsd seems to be the only choice for metrics, contextless errors everywhere, memory "leaks" (more like runaway memory use) that the developers swear are impossible because it's rust, overall just less mature across services written by both in house and oss teams
virtualritz today at 11:31 AM
I would add that Rust also has naming guidelines and sticking to them removes or at least minimizes the occurrence of another common topic of discussions on PRs/reviews.

In the article, if you were to mention & follow them GetUser() in Go becomes user() in Rust[1], not get_user().

[1] https://rust-lang.github.io/api-guidelines/naming.html#gette...

zjy71055 today at 2:23 AM
I was a Go engineer for years and have shipped a lot of Go. I never properly learned Rust.

Over the past year I've been using AI to write small Rust tools for myself — I barely read the code, and honestly it just works.

But for serious projects I expect to maintain long-term, I still pick Go. Today I want code I can actually own and reason about myself.

Give it a year or two and I probably won't be writing code by hand at all. Once the AI owns the code anyway, that reason disappears — and at that point Rust's guarantees win. So I suspect I'll end up leaning Rust.

JodieBenitez today at 2:36 PM
wpollock yesterday at 10:32 PM
Very nice write up! I am a fan of Rust and have little exposure to Go. That said, a couple of very minor points:

cargo audit is not built-in, it is 3rd party. (The comparison table near the top isn't clear about that, and the following text stating more is built-in for Rust than for Go might be confusing. I would suggest adding an asterisk to mark built-ins in that table.)

cargo watch has been in "maintenance mode" for some time. The author of that suggests cargo bacon instead.

danborn26 today at 8:59 AM
Great writeup. The section on error handling differences is spot on, especially how Rust's Result type changes the way you structure application flow.
h4kunamata yesterday at 11:48 PM
Read migrating from one hype to another, developers never learn or change, do they??

It feels like yesterday when every single project was moving to Go just because it was the new hype, that was until Rust was born.

We are already seeing projects dumping migration to Rust because the grass is not always greener on the other side.

We will be seeing this again, "Migrating from Rust to XYZ"

hasyimibhar yesterday at 10:57 PM
It is also easier to make your code deterministic with Rust vs with Go, which is incredibly useful if you need to perform deterministic simulation testing + property-based testing. I recently wrote a Postgres-to-Iceberg data mirroring tool [1] in Go, but I ported it to Rust because I wanted the ability perform DST without fighting Go's runtime [2]. But if the domain is not critical that warrants DST, I would still pick Go over Rust any day.

[1] https://github.com/polynya-dev/pg2iceberg

[2] https://www.polarsignals.com/blog/posts/2024/05/28/mostly-ds...

bnolsen today at 12:27 PM
I would think that you might have a better time going from go to zig. You would have to provide a pattern for implementing the interface model go uses.
3uler today at 10:34 AM
Golang is an amazing runtime with a bad language, one that conflates simple with easy. I view it the same way I view Java: a fine choice for a corporation, but nothing to love. Although Java’s gotten a lot better lately.
deleted today at 6:31 AM
nirui today at 5:49 AM
> It confuses easiness with simplicity

A lot of libs/packages in Go's stdlib also has this problem. They like to package everything in a very tight interface (very obvious example includes crypto/* and http), without exposing implementation detail to the end user.

Doing this of course has it's benefits, but if the feature provided by the stdlib slightly don't fit you needs, then you might have to write your own (potentially unsafe and/or less performant) one from zero.

Rust is great overall, but there's some oddities. For example their lib.rs / `mod` is very, very unintuitive, it felt overdesigned and unnecessarily complex (just see [their book]). I like what Go or Java did to their lib/package systems, it's much better that way.

[their book]: https://doc.rust-lang.org/stable/book/ch07-05-separating-mod...

netheril96 today at 2:46 AM
I've swinged between Go and Rust for my personal projects multiple times. For work, it is decided by the management so not my problem.

The biggest gripe I have with Go is the lack of *any* compile time check for mutex. Even C++ has extensions like ABSL_GUARDED_BY. For a language so proud on concurrency, it is strange not to have any guardrails.

AtNightWeCode today at 4:09 PM
Anybody who actually moved a set of services from Go to Rust? I've heard that in practice Rust uses more memory than Go for web services. When I ask LLMs I get the same answer as in the article. A 30-50% reduction but then also claims on how much memory Go uses. Which is about 5-10x more than our average service use.
phplovesong today at 3:01 PM
Go has warts, but projects like Lisette (https://lisette.run/) try to fix those. Go has bare syntax, as lack some (modern?) features. But imho it has a superb runtime, eg has a WAY better concurrency story than what you see in Rust.
0xfurai yesterday at 9:32 PM
The "when to enforce it" framing is what sticks with me. Go and Rust agree on safety, concurrency, simple deployment, but Go says "catch it in review" and Rust says "catch it before it compiles." The right answer depends entirely on how expensive a production incident is for you vs. how expensive slower iteration is.
HackerThemAll today at 9:37 AM
The datetime to string conversions in Go are devil's spawn.
amelius yesterday at 10:05 PM
Go has shorter and more predictable GC pauses. If a reference count drops to zero in Rust, it may take an unbounded time to free all the things it refers to (recursively if necessary).
up2isomorphism today at 8:03 AM
I never feel rust learning curve is steep. It is just everything is awkward, even more awkward than modern C++.
sylware today at 12:43 PM
What about AI assisted migration?

There was a signal to assist c++ to plain and simple C AI mass migration.

Removing any languages with ultra-complex syntax towards simple and plain C is always a good thing.

shevy-java today at 6:24 AM
Some years ago Go was all the hype rage.

Now Rust is the new Go.

I find that very confusing.

asplake today at 10:25 AM
I
fithisux today at 6:34 AM
JVM languages to Rust, I understand it somehow.

But Go to Rust???

It does not make any sense.

dilyevsky yesterday at 11:20 PM
> Under heavy allocation, P99 latency tails are noticeably worse than a Rust equivalent that simply doesn’t allocate on the hot path.

Lmao so not an equivalent then? Standard glibc malloc, which is default in rust, will also similarly degrade albeit for different reasons.

deleted yesterday at 9:51 PM
LoganDark yesterday at 11:10 PM
I still think rustfmt made a mistake by going with four spaces. It's basically inferior for everything except forcing everyone to use the same indentation width, which is actually a downside, since I constantly encounter two-space indent codebases that I can't read and also can't change to four spaces because it's not tabs. Also translating spaces to tabs visually is undecidable thanks to alignment, while the inverse is not true. Ugh.
DeathArrow today at 9:15 AM
>Go developers don’t usually come to Rust because Go is ā€œtoo slow.ā€ For most backend workloads, Go is plenty fast. People are generally a bit frustrated with Go’s verbose error handling, the danger of segmentation faults from nil pointers, and the lack of generics (for a long time) or any sophisticated type system features, such as enums or traits. Interfaces are not a worthy replacement for traits, and the Go standard library has some weird gaps, such as the lack of a Set type. (The idiomatic workaround is map[T]struct{}, which works fine in practice but is a tell that the type system isn’t quite carrying its weight.)

If those are issues, I rather use C#/.NET than expose both developers and AI agents to a cognitive overload.

However, those are not big issues to me, and at least in the present day, Go seems to excel at the things it is supposed to: backend and microservices. Sure, you can find some small issues with Go if you are really nitpicking, but you can find bigger issues with other languages. Sure, Go is boring as f..k, but I don't care and the agents don't mind, they love Go. Most people prefer reading Go than reading Rust. Go allows a fast way to production and for many startups and small companies, that matters a lot.

I don't hate Rust, and even use it - for where I think it makes sense, but for backend and microservices, Go seems a better fit.

As always, this is an opinion, derived from my personal experience, take it with a grain of salt, your experience might be different.

denysvitali today at 7:51 AM
The article seems to be just a way to say "Rust is better" - and it fails to do so by spreading misinformation such as the channels part (https://corrode.dev/learn/migration-guides/go-to-rust/#chann...) or making a fair comparison of pprof vs Rust's flamegraph.

It also skips entirely over debugging (delve vs gdb), IDE support, ecosystem (why the hell does Rust have N async runtimes?!), statically linking and so on.

A comparison between the performance of RLS / rust-analyzer (painfully slow) and gopls would be enough to kill the whole argument about developer happiness and productivity.

It even passes traits as a "reason to switch" to Rust - where in fact it would probably be a reason (IMHO) not to use it (together with lifetimes).

I think both languages are amazing, so a migration Go -> Rust (or Rust -> Go) makes no sense most of the time.

I've written code in both for a while now, so I know the pain and advantages of both.

For example, Go sucks at microcontroller stuff - in fact it's not even Go officially (see my presentation about porting "Go" to an ESP32-S3 [1]) - whereas Rust is amazing and even has a strong project behind (https://esp.rs) and amazing tooling (probe-rs & co).

What's also not addressed here is the Go ecosystem. The Go packages are one `go mod add` away (pkgs.go.dev) and the module owner guarantees v1 backwards compatibility for the whole lifetime of the module. This means that, no matter what happens, your dependencies will always be up-to-date with no migration struggle. This makes creating stuff for anything around the Kubernets ecosystem a breeze, you can literally import the types from another project and start your integration right away.

The most valuable part of the article seems the link to the opposite view (https://blainsmith.com/articles/just-fucking-use-go/). They're equally biased, but one is more straightforward than the other.

All in all, it's not a fair comparison and it's very biased (which is fair) - at the same time I think the idea behind the article is "wrong". If you find yourself migrating from Go to Rust (or vice versa), you're likely doing something wrong - and the performance gain is not the reason you're really doing it for.

[1]: https://docs.google.com/presentation/d/18jWccV-F2FguZiB5gXLk...

sspoisk today at 5:50 PM
[flagged]
kakuremi today at 4:48 PM
[flagged]
xuzhenpeng today at 8:56 AM
[flagged]
deleted today at 12:20 PM
tuptup today at 12:46 PM
[dead]
embirdating today at 10:02 AM
[dead]
treavorpasan yesterday at 9:11 PM
[dead]
DeathArrow today at 9:08 AM
TLDR:

>The other prior worth disclosing: I run a Rust consultancy; of course I’m biased!

amazingamazing yesterday at 9:07 PM
Rust is great. However in an agentic world go will win. Look no further than incremental build times. This, combined with high token costs mean that for a given application it simply will cost more to to write it in Rust than Go.

This can easily be justified for many usecases, but for your vanilla crud app, do you really need Rust?

Per the article, you are getting 20-50% better more performance with Rust. Not worth it unless your team was already fluent in Rust. Now consider a scenario where your team uses AI exclusively to code, now you are spending more time and tokens waiting around to consume large rust builds. As far as I know this is an inherent property of Rust to have its safety guarantees.

I think Rust makes sense for a lot of cases, but for a small web service, overkill and unnecessary imho. If someone ported their crud app from Go to Rust I would question their priorities.

Again I am speaking more in terms of software engineering economics than anything else. Yes, I know in a perfect world Rust binaries are smaller, performance is better and code more ā€œcorrectā€, but the world is hardly perfect. People have to push code quickly, iterate quickly. Teams have churn, Rust, frankly is alien for many, etc.