DEV Community

Cover image for πŸ”₯ The Hidden Superpowers of TinyGo: How to Run Go Code on Microcontrollers and Beyond!
Yevhen Kozachenko πŸ‡ΊπŸ‡¦
Yevhen Kozachenko πŸ‡ΊπŸ‡¦

Posted on • Originally published at ekwoster.dev

πŸ”₯ The Hidden Superpowers of TinyGo: How to Run Go Code on Microcontrollers and Beyond!

πŸ”₯ The Hidden Superpowers of TinyGo: How to Run Go Code on Microcontrollers and Beyond!

When most developers hear β€œGo”, they think high-performance backend services. When they hear β€œembedded programming”, they think C/C++. But what if I told you that you could write embedded firmware using Go? Welcome to the brave new world of TinyGo β€” the Go that fits into the tiniest chips and also works on the bleeding edge of WebAssembly!

🧠 TL;DR: TinyGo lets you write Go code that compiles down to run on ARM Cortex-M microcontrollers and in the browser using WebAssembly. It’s faster than MicroPython, easier than C, and it’s real, idiomatic Go.

In this post, we're diving deep into TinyGo, uncovering its incredible potential for IoT, edge computing, and WASM. Not only are we going to explore working examples on Arduino and WebAssembly, but we'll also see how TinyGo can be the go-to (pun intended) tool for writing safe, maintainable embedded code without sacrificing performance.


πŸš€ What Is TinyGo?

TinyGo is a Go compiler that targets tiny devices and WebAssembly using LLVM.

  • Supports ARM Cortex-M (e.g., STM32, Arduino Nano 33 IoT)
  • WebAssembly (WASM) that runs in browsers or standalone
  • Esperanto for Go devs entering embedded space

Unlike regular Go, the Go runtime in TinyGo is a tiny subset β€” necessary to keep binaries small (you know, under 32 KB kinda needs that 🀏).


⚑ TinyGo vs. MicroPython vs. C β€” A Quick Showdown

Language Performance Memory Footprint Dev ergonomics Community
C/C++ πŸš€πŸš€ πŸͺΆ Lowest πŸ˜΅β€πŸ’« Steep learning Huge
MicroPython 🐌 Slow 🧠 Medium 😊 Easy Great
TinyGo ⚑ Fast 🧠 Low 😎 Smooth (Go!) Growing

What's the catch? Not all Go features work (e.g., reflect, interface{} can be limited).


πŸ§ͺ Real Example #1: Blinking an LED on Arduino Nano 33 IoT with TinyGo

Let’s start with a classic: the Blink.

πŸ”§ Requirements

βœ… Code Example (blink.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)
    }
}
Enter fullscreen mode Exit fullscreen mode

πŸ—οΈ Build and Flash

tinygo flash -target=arduino-nano33iot blink.go
Enter fullscreen mode Exit fullscreen mode

And voilΓ  β€” blinking like a champ πŸŽ‰


🧠 Real Example #2: WebAssembly and TinyGo in the Browser

TinyGo compiles to WASM with a much smaller output compared to Go’s default WASM toolchain.

Sample Code (main.go)

package main

import (
    "syscall/js"
)

func main() {
    alert := js.Global().Get("alert")
    alert.Invoke("Hello from TinyGo WASM πŸš€")
}
Enter fullscreen mode Exit fullscreen mode

Build It:

tinygo build -o main.wasm -target wasm main.go
Enter fullscreen mode Exit fullscreen mode

Embed in HTML:

<!DOCTYPE html>
<html>
<head><meta charset="utf-8"></head>
<body>
  <script>
    const go = new Go();
    WebAssembly.instantiateStreaming(fetch("main.wasm"), go.importObject).then(result => {
      go.run(result.instance);
    });
  </script>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

πŸ‘‰ When you load the page β€” BAM! Alert pops up from Go-WASM.

πŸ’Ž Real World Usage?

  • Create WASM libraries in Go
  • Replace heavy JavaScript modules with TinyGo-WASM
  • Target both embedded devices and browsers with the same code πŸ”₯

πŸ•ΉοΈ Bonus: Accessing Sensors on Microcontrollers

Let’s read real-world data β€” say from a temperature sensor like the DHT11.

Sample Code:

import (
    "time"
    "machine"
    "tinygo.org/x/drivers/dht"
)

func main() {
    sensor := dht.New(machine.D2, dht.DHT11)
    sensor.Configure()

    for {
        temp, humidity, err := sensor.ReadRetry(10)
        if err == nil {
            println("Temp:", temp, "Β°C",
                " Humidity:", humidity, "%")
        }
        time.Sleep(time.Second * 2)
    }
}
Enter fullscreen mode Exit fullscreen mode

Build and flash again β€” now your Go code reads real-world data ✨


🧠 Why TinyGo Matters

Let’s break the paradigm:

  • Go is safe, typed, and modern
  • Embedded dev is bug-prone, manual, and niche
  • TinyGo bridges them β€” making embedded and web apps safer and more accessible

πŸ’‘ Use TinyGo to write libraries usable across:

  • A microcontroller firmware (e.g. Arduino)
  • A browser via WebAssembly
  • A command-line diagnostic tool (std Go)

πŸ‘·β€β™‚οΈ What's Missing?

  • Third-party libraries + driver support is growing but less than C or MicroPython
  • No net/http unless you're on appropriate targets
  • Async concurrency and goroutines are limited (but supported)

Contribute and grow the ecosystem if you love Go!


🚨 Final Verdict: Use Cases in the Wild

Use Case Why TinyGo?
IoT Device SDKs One codebase for browser + device testing
Plants watering systems 🌿 Go + DHT + Servo control
WASM-Libs for JavaScript Replace bloated JS with tiny fast WASM
EdTech for kids Easier than C, stronger than MicroPython
Low-power Wearables Long battery life with low memory footprint

πŸ“Ž Resources


♻️ Wrapping Up

TinyGo is not here to β€œreplace C”. It’s here to open doors. If you love Go, and you want to get your hands dirty in hardware or compile blazing fast WebAssembly apps, give TinyGo a try.

Don’t just code APIs. Build electric cats. Laser bots. Air-qual sensors in your kitchen. And make the browser do what JS never could.

Go tiny β€” think big.

Are you using TinyGo in production? Got questions about drivers or WebAssembly? Share them in the comments below!


✨ If you're exploring embedded Go or experimenting with TinyGo + WASM for real-world applications β€” we offer tailored research and development services to support your innovation!

Top comments (0)