Written by: ekwoster.dev on Sun Aug 24

🔥 Why Everyone Is Sleeping On TinyGo: Run Go on Microcontrollers and the Web (WASM) Today!

🔥 Why Everyone Is Sleeping On TinyGo: Run Go on Microcontrollers and the Web (WASM) Today!

Cover image for 🔥 Why Everyone Is Sleeping On TinyGo: Run Go on Microcontrollers and the Web (WASM) Today!

🔥 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?

  • Docs: https://tinygo.org/docs/
  • Repo: https://github.com/tinygo-org/tinygo

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.