Adventures in Migrating from Go to Zig and Rust with Claude Code
How good are AIs with different languages?
I’m very happy with Claude Code generating code in my projects. I often hear that AI does not work for developers, ROI for AI fails, there is no measurable speedup. I suspect there are different factors why I’m successfully using an AI to write 99% of code while many others fail.
One of those reasons might be the usage of Go. Go is AI friendly because:
Many libraries to use
Many examples for AIs to train on
Simple syntax - not difficult for AIs to get right
One way to do things
Compile time checking of generated code
Explicit constructs - lots of boiler code noise, e.g. error handling (compare to Rust “Magic”) that helps AI understand what is going on
No major changes for the last 10 years, documentation that is 5 years old is still mostly relevant (Big changes like introduction of Context are few and far).
I have a small project called Hop which I use to manage my static website Amazing CTO for my CTO Coaching on Bunny CDN. With Hop I can change 302 redirect rules, push files to the CDN, manage and check DNS and minify HTML, CSS, JavaScript and images (PNGs to WEBP).
Using Hop we’ll find out two things:
Do Zig and Rust work as well with AI as Go does
Are Zig and Rust much more performant than Go and it makes sense to migrate projects
To test this, I converted the Go project both to Zig and to Rust.
Zig
Start with the new kid on the block: Zig. Touted being as fast as C but safer. Having a fast compiler and nice error semantics. We’ll try to convert our little tool to Zig.
First we let Claude generate a plan_zig.md file for the migration and tell Claude what we want it to do. Examine the Hop code, extract the functionality, find Zig replacements for the Go libraries used, migrate the code, build and test the result.
As usual I asked Claude after it finished the plan to check the plan for details and make sure it works with the code. To read the documentation again and make sure the plan works. One issue were dependencies. We iterated over the plan for finding the right dependencies replacements. Many libraries that are available in Go are not available in Zig, and it had trouble to also find C libraries e.g. for minify - Claude suggested to fork cminify and make it a C library and I agreed. After we were finished with refining the plan I asked Claude if it was “confident” to make the plan work, it wasn’t and made some changes, added some lines and checked more documentation.
When starting coding, Claude failed miserably. It could not get IO working because Zig recently changed how it does IO. Zig was confusing as it had old documentation an new documentation. Documentation on the Zig site was subpar, API docs being spotty and the website and the internet lacking great tutorials. Giving 4 URLs to Claude to check how IO works now didn’t work and Claude was not able to get something compiled for half an hour.
I stopped the migration to Zig at that point.
Rust
On to Rust, which is much older than Zig and should not be a challenge because of lacking documentation or fast changes. Rust might be a challenge because of the complicated syntax though, can Claude manage that?
Going the same route with the plan and iterating over it as we did wit Zig, Claude had problems finding dependencies, at one point Claude wanted to minify JavaScript by wrapping it in <script> and using a HTML minifier instead of using e.g. minify-js
We did not find a library to convert fonts into the smaller WOFF2 (Go had a library), and Claude suggested to use C++ which I refused, I didn’t want to drag in a C++ toolchain. As I can convert the fonts once and for all, I dropped the font-conversion requirements.
Claude worked for several long minutes and in the end: Compiled on first try.
Contrary to Zig, Claude had no problem converting the project to Rust, and make it compile.
Going into the details of what Claude did, revealed many problems though. Command line arguments were different between the versions, e.g. —key vs. —api-key, and even parameters were different —zone <zonename> vs —pull-zone-id <zoneid> with different semantics. And then some parameters were missing completely and some were added:
There are big differences in the CLI API of both versions, but differences do not stop there. Both versions have different functionality, the Rust version (Rhop) has a JSON rule file which was not part of the original Hop application.
Learning: My prompt should have been more specific to copy the parameters verbatim and make sure the CLI API stays compatible.
Beside that, the “rules list” command did not work, it listed all Edge rules of the project not only redirects, where the Go version would only print redirect rules (as intended). Minify did not work. The minify command in Rhop did not copy files it could not minify but ignored them. Second, when minify had an error with a JS file or CSS file, because it could not parse it, Rhop did not copy the file but also ignored it. The Go version creates a responsive srcset of WEBP files from one PNG, Rhop only converts one PNG to one WEBP file - forgetting the responsiveness functionality.
The HTML was also broken, the minifier was too aggressive to minify HTML which resulted in broken pages. Then Claude tuned the minifier down to be less aggressive, but it still broke the page. What happened? It turned out some of my pages were not correct HTML to begin with - Hop with Go was just more forgiving than Rhop with invalid HTML.
A short Claude Code planning and coding session removed those bugs and made Rhop work.
Eureka! We converted a Go project successfully to Rust.
Let’s compare both versions, the Rust and the Go one (You remember Zig failed). I focus on the minify functionality here. The difference in the minified size between the Go and the Rust version wasn’t that big:
The difference in runtime also wasn’t as big as I had hoped - Rust is touted as a very fast language rivaling C but the results felt mixed:
A reduction of running time of 30s is not nothing but it’s not twice as fast with no cache. It is much faster when we’re mostly CPU bound when all images are cached and skipped and only HTML minifying is applied. In this case Rust is ~4x faster - though for my website the Go version is fast enough with 6 seconds. Perhaps the Rust code wasn’t very optimized? Telling Claude Code to optimize the Rust code, it changed the parallelization strategy, applied read optimizations, optimized copies and more, and the time went up to ~100s. Go figure.
How much code did Claude produce? Comparing the implementations, the versions are similar in size:
The implementation in Rust has less code than Go, something to be expected because Go is more verbose, but also surprising as LLMs often add more lines of code and are very verbose. On top it looks like Claude Code is not very noisy by adding lots of comments, as LLMs have also been accused of.
Overall at this point I feel the conversion was not satisfying. Claude Code totally failed with Zig, and the Rust version of Hop was only superficially the same. From the wrong parameters, to the missing features - the implementation was totally different - e.g. the WEBP conversion didn’t include responsive output. Perhaps a better prompt is needed to make this happen.
In the grand scheme of things though, it was amazing to convert between programming languages in a few hours, something which would have taken days for a developer to accomplish - if I could make them start this dreadful task at all. As this will only get better over time, we are moving to a place where programming languages do no longer matter as we can covert between languages and frameworks. Indeed a conversion prompt, that tackles the main dependencies, based on what works, between projects to guide the LLM, could make this conversion even faster.
Second we wanted to see if a conversion makes sense because of performance gains, and if an LLM can handle Zig and Rust as well as Go. From a language perspective, the LLM failed with Zig but Rust seems to work as well as Go with AIs. My usual problems when writing Rust code did not occur. I had no borrow checker problems (though I do suspect the AI uses quite some Arc<>) - the second reason I left Rust stayed with me: compile times in Rust are atrocious compared to Go.






