Rewriting a .NET Blazor app in Go without losing parity
"Rewrite it in Go" is a satisfying sentence. It is also, in this case, mostly a lie — and noticing that early is what made the rewrite tractable.
Blazor Server is the UI
The original NFTMixer is a C#/.NET 6 Blazor Server app. Its .razor files are
not templates — Blazor Server is a stateful framework that renders on the server
and pushes DOM diffs to the browser over a websocket. Go has no equivalent. So
while the generation engine, compositing, database access, S3, and wallet auth
all port to Go cleanly, roughly 70% of the work was frontend, rebuilt from
scratch in Next.js. Budgeting for that up front is the difference between a plan
and a surprise.
Parity means behaviour, not files
Full parity does not mean porting every file. Several things were deliberately left behind because they were dead or dangerous:
- an unauthenticated full-database-dump endpoint,
- unfinished IPFS publishing that never actually uploaded,
- entire generations of superseded components that were referenced but unreachable.
Porting those would have been faithfully reproducing debt.
Fixing the things that were simply broken
The most interesting part of a rewrite is the bugs you refuse to carry over. The original's "authentication" believed whatever wallet the browser claimed — no signature, anywhere:
Old flow: browser says "I am 0xADMIN…" → server believes it.
New flow: server issues nonce → wallet signs → server RECOVERS the address
from the signature (go-ethereum). Same effort, actually secure.
Alongside real SIWE, ownership is now derived from the session rather than a URL parameter, and sessions expire via a Mongo TTL index instead of living forever in an in-memory map.
Deliberate parity breaks
A rewrite is also a chance to be correct where the original was wrong: metadata now follows the OpenSea standard instead of a flat dictionary, and every layer is resized to the output dimensions so non-uniform art composites without misalignment. Those are intentional divergences — parity with the intent, not the mistake.