A map in Go (golang map, golang maps, map golang, maps golang, map in go) is a built-in hash table: keys are unique, values can repeat, and lookups are fast on average. If you know associative containers as a Python dictionary or a “hash map” in other languages, the same mental model applies—often people also say golang dictionary when searching. This page covers the golang map literal, make, the comma-ok idiom, delete, for range, stable ordering tricks, and what people mean by golang global map (package-level variables and concurrency). For structured records with fixed fields, compare with structs.
Tested with Go 1.24 on Linux.
Map type: map[K]V and comparable keys
The type form is map[KeyType]ValueType. KeyType must be comparable (for example string, int, or pointers); ValueType can be almost anything, including slices, structs, or another map.
Keys must be unique. If you repeat the same key in one literal, the compiler rejects it (duplicate key … in map literal).
The zero value of a map is nil. Reading from nil is safe (you get the value type’s zero value and ok == false in the comma-ok form), but assigning to a nil map panics:
package main
import "fmt"
func main() {
var m map[string]int
fmt.Println(m, m == nil)
// m["k"] = 1 // panic: assignment to entry in nil map
}map[] trueInitialize before writing with a golang map literal or make:
package main
import "fmt"
func main() {
lit := map[string]int{"ada": 1, "bob": 2}
fmt.Println("literal:", lit)
m := make(map[string]int)
m["ada"] = 1
fmt.Println("make:", m)
}literal: map[ada:1 bob:2]
make: map[ada:1]make(map[K]V, hint) accepts an optional capacity hint for preallocating buckets; the map still grows as needed (spec: make).
Reads, writes, delete, and the comma-ok idiom
Indexing m[k] returns the stored value or the value type’s zero if the key is missing—which is ambiguous for types like int where 0 might be real data. Use two return values:
package main
import "fmt"
func main() {
scores := map[string]int{"ada": 42}
v, ok := scores["ada"]
fmt.Println(v, ok)
v2, ok2 := scores["missing"]
fmt.Println(v2, ok2)
}42 true
0 falsedelete(m, key) removes an entry; it is a no-op if the key is absent.
package main
import "fmt"
func main() {
m := map[string]int{"a": 1, "b": 2}
delete(m, "a")
fmt.Println(m)
}map[b:2]for range on maps in golang (unordered iteration)
for k, v := range m visits every pair, but iteration order is randomized and must not be relied on for stability across runs. That is why two runs can print keys in different orders even if the map contents are identical.
To process keys in a fixed order, copy keys to a slice and sort (numeric example):
package main
import (
"fmt"
"sort"
)
func main() {
users := map[int]string{100: "John", 23: "Mary", 54: "Paul", 21: "Josh"}
keys := make([]int, 0, len(users))
for k := range users {
keys = append(keys, k)
}
sort.Ints(keys)
for _, k := range keys {
fmt.Println(k, users[k])
}
}21 Josh
23 Mary
54 Paul
100 Johngolang global map: package-level maps and concurrency
A “global map” usually means a package-level variable, for example:
var userIDs = make(map[string]int) // initialized, not nilThat is convenient for registries or caches, but the Go memory model still applies: unsynchronized concurrent writes to an ordinary map are undefined behavior and can crash. Patterns:
- Guard the map with
sync.Mutexorsync.RWMutexwhen many goroutines read and write. - Use
sync.Mapwhen you have lots of disjoint keys or frequent loads with rare stores (documented as a niche optimization, not a drop-in for every map). - Prefer passing a map down the call stack or storing it in a struct you own so tests can substitute fakes.
For printing map types in debugging, see print variable type.
Standard library maps helpers (Go 1.21+)
The maps package provides utilities such as maps.Clone, maps.Equal, and maps.Copy for common map workflows without reimplementing them by hand.
Summary
Maps in golang give you fast key/value storage with a compact literal syntax and make for empty, ready-to-write tables. Remember the distinction between a nil map (reads ok, writes panic) and an empty-but-initialized map, use the comma-ok form when zero values are ambiguous, and treat for range over a map as intentionally unordered unless you sort keys yourself. A golang global map is just a package-level value: safe only with clear ownership or explicit synchronization. If you outgrow ad-hoc maps for configuration-shaped data, reach for structs or dedicated types.

