🔥 Why Everyone Is Sleeping On TinyGo: Run Go on Microcontrollers and the Web (WASM) Today!
What if I told you that your Go programs could run not only on Linux servers but inside a browser or on a microcontroller smaller than your thumb? Welcome to the world of TinyGo 👾.
When you hear "Go," you probably think cloud servers, APIs, or blazing-fast concurrency. But there’s a lesser-known sibling in the Go ecosystem—and it packs a serious punch in the embedded and WebAssembly (WASM) space. It's called TinyGo, and it's about to blow your dev hat off 🎩💨.
In this post, we’re diving deep into:
- What TinyGo is and why it matters.
- Real pain points it solves for embedders and web devs.
- Running Go on an Arduino.
- Compiling Go to WASM that’s smaller, faster, and install-free.
- Code examples and tips to get you started.
Let’s go (pun intended).
🧠 Wait, What Is TinyGo?
TinyGo is a Go compiler created for resource-constrained environments. While the official Go compiler (gc) is focused on desktop/server environments, TinyGo is designed for microcontrollers and even WebAssembly targets.
It allows you to:
- Write Go code for microcontrollers like Arduino, BBC micro:bit, Raspberry Pi Pico, etc.
- Compile Go into WASM that’s small enough for frontend production use.
- Share code across embedded and web-based applications (yes, actual code reuse).
😬 Real-World Pain Points It Solves
Pain #1: Embedded Devs Are Still in 1998
If you’ve done embedded dev, you're familiar with this:
- Cryptic C/C++ syntax
- 30 minutes to debug a missing semicolon
- Toolchains from the Windows XP era 🤢
With TinyGo, you get:
- Simple Go syntax
- Modern tooling (VSCode, go fmt, etc.)
- Concurrency via goroutines (yes, it works in TinyGo!)
Pain #2: WebAssembly Builds Are Thick
Go WebAssembly files via the official compiler can be as large as 2MB+.
That’s a non-starter for client-side app performance.
TinyGo generates WASM binaries often under 500 KB, sometimes as little as 100 KB depending on the app.
That’s a 4–20x size reduction ⏬
🦾 Code Example: Blink an LED Using Go 🎇
Let’s run a Go program on an Arduino (UNO, Nano, or whatever you're using).
✅ Prerequisites
- A supported microcontroller (like Arduino Nano with ATmega328P)
- Install TinyGo: https://tinygo.org/getting-started/
brew tap tinygo-org/tools
brew install tinygo
- Install avrdude for flashing Arduino:
brew install avrdude
🔌 Connect and Flash
Here’s our example main.go:
package main
import (
"machine"
"time"
)
func main() {
led := machine.LED
led.Configure(machine.PinConfig{Mode: machine.PinOutput})
for {
led.High()
time.Sleep(time.Millisecond * 500)
led.Low()
time.Sleep(time.Millisecond * 500)
}
}
🔥 Compile and Flash to Your Microcontroller
tinygo flash -target=arduino main.go
Boom—your LED should now be blinking at half-second intervals, using Go.
🕸️ Code Example: WebAssembly With Go + TinyGo
Here's a minimal WASM app in Go that runs in the browser:
main.go
package main
import (
"syscall/js"
)
func add(this js.Value, args []js.Value) interface{} {
a := args[0].Int()
b := args[1].Int()
return js.ValueOf(a + b)
}
func main() {
js.Global().Set("add", js.FuncOf(add))
select {} // Keep alive
}
Build for WASM
tinygo build -o add.wasm -target wasm main.go
HTML Interface: index.html
<!DOCTYPE html>
<html>
<body>
<h1>WASM Add in Go</h1>
<button onclick="callAdd()">Add 3 + 4</button>
<p id="result"></p>
<script>
async function init() {
const go = new Go();
const wasm = await WebAssembly.instantiateStreaming(fetch("add.wasm"), go.importObject);
go.run(wasm.instance);
}
function callAdd() {
const result = add(3, 4);
document.getElementById("result").innerText = `3 + 4 = ${result}`;
}
init();
</script>
</body>
</html>
Open in any browser—no server needed. Just serve via a static file server.
Compare WASM Sizes
- Official Go WASM: ~2–4 MB
- TinyGo WASM: ~150–300 KB
✅ This is production-safe. No more bundling bloated WASM modules.
⚖️ Trade-offs: What’s the Catch?
- TinyGo doesn’t support the entire Go standard library (yet)
- Runtime behavior is limited (e.g., GC is simple, no reflection)
- You may need to refactor traditional Go code to work
Still, for many constrained environments or WASM work, these are acceptable trade-offs.
✈️ Reuse Code Between Embedded + Web
If you’re building, say, an IoT device and a dashboard:
- Write computation logic in pure Go
- Compile one version for the device (embedded)
- Compile to WASM for the browser
Example: Shared Package
// mathops/math.go
package mathops
func Add(a, b int) int {
return a + b
}
Import into your embedded firmware and also into your WASM frontend.
That’s code reuse between hardware and frontend, in Go.
🧠 Final Thoughts: Why TinyGo Is the Hidden Gem
In a world where:
- Embedded development feels ancient
- WebAssembly is gaining traction but has usability barriers
TinyGo is slicing through the noise with a modern, minimal, and cross-domain approach.
Whether you're an embedded dev tired of C/C++ or a frontend junkie exploring WASM, give TinyGo a weekend. You'll be amazed.
✅ Ready to Start?
Let me know what you build with it! 🚀
If you liked this post, share it or tweet me at @yourhandle. Want a tutorial on TinyGo with Bluetooth or sensor integration? Let me know 👇
🛠️ If you need help building production-ready applications in TinyGo or shipping WASM-based features to the frontend — we offer such services.