— notes

Go Maps Iteration Order

2 min read#go
On this page
  1. The non-negotiable fact
  2. What is actually happening inside a Go map
  3. Why the output looked sorted
  4. A simplified mental model

I was working on a minimal word counter. Read from stdin, normalize the input, increment the value for the keys in a map[string]int. The output looked sorted. Alphabetically sorted.

I ran it again. Same order. Added more input. Still sorted.

At that point, my instincts kicked in. Go maps are unordered. I knew that. So why was the output behaving so politely?

The non-negotiable fact

Go maps do not guarantee iteration order. Ever. The language spec is explicit.

What is actually happening inside a Go map

A Go map is a hash table. Iteration walks buckets in a runtime-defined sequence, not key order.

graph LR
    subgraph "Hash Function"
        H["hash(key)"]
    end
    K1["a"] --> H
    K2["b"] --> H
    K3["m"] --> H
    K4["1"] --> H
    H --> B0["Bucket 0\n1"]
    H --> B1["Bucket 1\n2"]
    H --> B3["Bucket 3\na"]
    H --> B4["Bucket 4\nb"]
    H --> B6["Bucket 6\nm"]

Why the output looked sorted

Small number of keys, short ASCII strings, no map resizing during insertion. Under these conditions, hash values distribute nicely across buckets, and the bucket layout in memory often correlates with lexical order. By coincidence.

graph TD
    S["Small ASCII key set"]
    L["Large / diverse key set"]
    S --> O1["Appears sorted (coincidence)"]
    L --> O2["Visibly unordered (reality)"]

A simplified mental model

Input keys:  a   b   m   x   y   z   1   2   9

Buckets in memory order:
[0] [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11]
 1   2   9   a   b       m           x    y    z

Iteration walks buckets left to right:
1 2 9 a b m x y z

Digits first. Then letters. Within each group, alphabetical-looking. No sorting happened. Change the input distribution, force collisions, trigger a map resize, and this illusion breaks instantly.

Deterministic-looking behavior does not imply guarantees.