Go

Go for Embedded/IoT

This closing chapter is the honest answer to a question the whole domain has been building toward: where does Go actually fit next to Embedded C and embedded C++? The short version: rarely on a tiny microcontroller running standard Go, sometimes on one running TinyGo, and genuinely often on the Linux-class device or cloud gateway sitting one layer up from it.

Quick reference
What it is
Standard Go's runtime requirements vs. TinyGo, a separate compiler targeting microcontrollers directly, plus where Go fits in a typical IoT architecture regardless of which compiler is used.
Mental model
Standard Go assumes an operating system underneath it; TinyGo strips that assumption away for bare metal, at the cost of a smaller standard library and a still-present (if simpler) garbage collector.
Key numbers
Standard Go's runtime needs several MB minimum — far beyond a typical microcontroller's RAM; TinyGo brings that down dramatically, into the range of small MCUs with tens of KB.
Reach for it when
An IoT gateway, an edge server aggregating sensor data, or a Linux-class embedded board (an SBC) — not, typically, the tiny sensor-node MCU itself.

Why standard Go doesn't fit tiny microcontrollers

Every chapter in this domain has been standard Go, which assumes real resources most microcontrollers don't have:

None of this is a Go design flaw — it's the same tradeoff Introduction to Go's comparison table named from the start: Go optimized for programmer productivity on networked systems, not for the tightest possible resource footprint.

TinyGo

TinyGo is a separate compiler (not a fork of the language) that compiles a meaningful subset of Go directly for microcontrollers and WebAssembly, built on LLVM — the same compiler infrastructure much of the C/C++ embedded toolchain world already uses:

// blink.go — runs on an actual microcontroller via TinyGo
package main

import (
    "machine"
    "time"
)

func main() {
    led := machine.LED
    led.Configure(machine.PinConfig{Mode: machine.PinOutput})

    for {
        led.High()
        time.Sleep(500 * time.Millisecond)
        led.Low()
        time.Sleep(500 * time.Millisecond)
    }
}
tinygo flash -target=arduino blink.go   # compiles AND flashes to real hardware

This still has a (simpler, smaller) garbage collector and still uses goroutines — TinyGo doesn't remove Go's core design, it re-targets the compiler backend and trims the standard library to fit. It's a real, working option for microcontroller-class Go, not a toy — but it's a genuinely different, narrower tool than the standard Go compiler used throughout the rest of this domain.

Where Go actually fits in IoT

The honest, practical answer is one layer up from the sensor node itself:

Sensor/actuator node
Almost always C, occasionally TinyGo, rarely standard Go — tightest resource constraints, closest to the hardware.
IoT gateway
A genuinely strong fit for standard Go — aggregating data from many sensor nodes, running on real Linux-class hardware (an SBC or small server) with megabytes of RAM to spare.
Edge/cloud backend
Go's strongest, most common home — the networked-services use case Go was actually designed for, per Introduction to Go.

A typical device-to-cloud stack, with the language layer named

A typical IoT stack: a C or TinyGo sensor node talks to a Go-based gateway, which talks to a Go-based cloud backend Sensor node C, occasionally TinyGo IoT gateway standard Go, strong fit Cloud backend Go's home turf The tightest resource constraint is on the left — Go's fit gets stronger moving right
See Networking's IoT Architecture chapter for this same device/gateway/cloud shape covered in full, independent of language.

Real-world applications

Gotchas

Field notes