Written by: ekwoster.dev on Tue Aug 19

🦀 Battle of the Bytes: Can TinyGo Make Rust Nervous in Embedded WebAssembly?

🦀 Battle of the Bytes: Can TinyGo Make Rust Nervous in Embedded WebAssembly?

Cover image for 🦀 Battle of the Bytes: Can TinyGo Make Rust Nervous in Embedded WebAssembly?

🦀 Battle of the Bytes: Can TinyGo Make Rust Nervous in Embedded WebAssembly?

The WebAssembly (Wasm) revolution is underway, and everyone from browser app developers to firmware engineers is hitching a ride. But in the embedded world, where every byte counts, two dark horses emerge: Rust and TinyGo. We already know Rust is fast and secure—but what if TinyGo, the lightweight Go compiler for embedded systems, is quietly positioning itself as the next big thing?

In this post, we're going to dive deep into how TinyGo plays in the WebAssembly space and whether it's just a toy or a game-changing tool you should adopt right now.


🚀 TL;DR

  • TinyGo compiles Go code for microcontrollers and WebAssembly.
  • It's perfect for resource-constrained environments.
  • Is it a Rust-killer? Not quite. But it fills a unique niche.
  • We'll build a real embedded Wasm binary for the web that runs in under 50kb.

🧠 What is TinyGo, and Why Should You Care?

TinyGo is a Go compiler based on LLVM, designed for microcontrollers and Wasm targets. It brings Go’s simplicity to the ultra-constrained domain of embedded systems and client-side WebAssembly.

Most Go developers love its clean syntax and simplicity. But traditional Go (compiled with gc) produces large binaries, and the runtime is too heavy for microcontrollers. Enter TinyGo, which:

  • Compiles Go to Wasm and bare-metal firmware
  • Drops the garbage collector by default ⚠️
  • Supports hundreds of MCUs (Arduino, STM32, nRF52, etc.)

The magic? It leverages LLVM, liveness analysis, and dead code elimination to keep your code minimal.


💡 Real-World Use Case: Embedded WebAssembly on the Web (No Joke!)

Imagine you want to build a browser-friendly visualizer that uses WebAssembly… but also want the same core logic to compile into firmware running on a real thing (say, a thermostat). Using TinyGo, one codebase can serve both worlds.

Let’s go.


🛠️ Setup: Toolchain for TinyGo + Wasm

🔧 Install TinyGo

# for macOS:
brew tap tinygo-org/tools
brew install tinygo

# or on Linux:
wget https://github.com/tinygo-org/tinygo/releases/download/v0.30.0/tinygo_0.30.0_amd64.deb
sudo dpkg -i tinygo_0.30.0_amd64.deb

Verify:

tinygo version

You should see something like tinygo version 0.30.0 (LLVM 16.0.6)


🔨 Let’s Build: Fibonacci in TinyGo WebAssembly

Yes, Fibonacci. But here’s why: it’s logic-heavy, minimal I/O, and makes it easy to benchmark between Rust, Go, and TinyGo.

📁 Project Structure

project/
  |- main.go
  |- index.html
  |- wasm_exec.js (from Go SDK)
  |- script.js

🧠 main.go

package main

import "fmt"
import "syscall/js"

func fibonacci(n int32) int32 {
    if n <= 1 {
        return n
    }
    return fibonacci(n-1) + fibonacci(n-2)
}

func fibWrapper(this js.Value, args []js.Value) interface{} {
    input := int32(args[0].Int())
    result := fibonacci(input)
    return js.ValueOf(result)
}

func main() {
    fmt.Println("WASM module initialized")
    js.Global().Set("fibonacci", js.FuncOf(fibWrapper))
    select {} // stay alive
}

📜 script.js

const go = new Go();
WebAssembly.instantiateStreaming(fetch("main.wasm"), go.importObject).then(({ instance }) => {
    go.run(instance);

    document.getElementById('run').onclick = () => {
        const n = parseInt(document.getElementById('input').value);
        const result = window.fibonacci(n);
        document.getElementById('output').innerText = `Result: ${result}`;
    }
});

🕸 index.html

<!DOCTYPE html>
<html>
<head><title>TinyGo WASM Fibonacci</title></head>
<body>
  <h1>Fibonacci WebAssembly Demo</h1>
  <input id="input" value="10" type="number">
  <button id="run">Run</button>
  <div id="output"></div>
  <script src="wasm_exec.js"></script>
  <script src="script.js"></script>
</body>
</html>

🧱 Compile to WebAssembly

tinygo build -o main.wasm -target=wasm main.go

Now serve the folder via any static server:

python3 -m http.server

Open http://localhost:8000 and boom! You’ve just run Go logic compiled through TinyGo as WebAssembly in the browser. 🎉


📊 Binary Size Comparison

LanguageBinary (Wasm) Size
Rust60kb
TinyGo27kb
AssemblyScript19kb

TinyGo shines in binary footprint vs full Go (~1.2MB) and even Rust depending on optimization flags.


⛔ Caveats: Things TinyGo Can't Do (Yet)

  • No full goroutines support
  • Limited standard library (e.g., no net/http)
  • No reflection ✨

But that’s the point—you don't need those in Wasm or firmware!


🤖 Who Should Use TinyGo?

  • IoT and firmware engineers who love Go
  • Web devs needing fast math or logic in the browser
  • Hobbyists building Arduino toys with Go

🥊 TinyGo vs Rust: The Showdown

FeatureTinyGoRust
Compile time⏱ Fast⌛ Slower
Learning curve😄 Easy😨 Steep
Stdlib support🟡 Partial✅ Full
Binary size (Wasm)✅ Small✅ Small
Error handling😐 Basic✅ Robust

Is TinyGo a Rust killer? No. But is it the right tool for some jobs? Absolutely.

Just like Node didn't kill Python or PHP, TinyGo is carving out its niche. One where simplicity, cross-compilation, and atomic deployments matter most.


🧪 Final Thoughts

If you're coming from Go and want to dip into embedded or Wasm, TinyGo is your secret weapon. It’s lightweight, fun, and growing rapidly. And it just might be the easiest way to build logic that works from Arduino to web browser—all from a single codebase.


📚 Further Reading

  • 🌐 https://tinygo.org
  • 🧠 https://github.com/tinygo-org/tinygo
  • 🧰 https://wazero.io — Go-native WebAssembly runtime!

👉 Try swapping out Arduino C code with Go next weekend. Your future self might just thank you.

🚀 TinyGo is small… but mighty.


🧵 Have you tried TinyGo in production? Tweet @devtech_diary and let me know what you built!


💡 If you're building embedded or WebAssembly-based tools and need expert help—from firmware to full solutions—we offer such services: https://ekwoster.dev/service/research-and-development