Go const map and constant map: Why They Are Not Allowed and What to Use Instead

Go does not allow golang const map or golang map const literals: constants must be compile-time values of allowed types. Use a golang global map with var and init, getters over unexported maps, or functions that return maps; the same idea applies to a golang constant slice.

Published

Updated

Read time 4 min read

Reviewed byDeepak Prasad

Go const map and constant map: Why They Are Not Allowed and What to Use Instead

People search for golang const map, golang constant map, go const map, golang map const, and const map golang because other languages allow frozen map literals. In Go, a go constant map declaration is a compile-time error: const only applies to values the language spec treats as constants (booleans, numbers, strings, runes, and certain combinations). A golang global map as a var initialized once is the usual substitute, together with init, sync.Once, or small getter functions when you want constant map golang style stability from the caller’s point of view. The same rules explain why a golang constant slice cannot be a const literal either.

Tested with Go 1.24 on Linux.


Why there is no golang const map

Maps (and slices, structs containing them, and most user-defined types) are not constant types in Go. You cannot write:

go
const m = map[string]int{"a": 1} // compile error

The compiler rejects that for the same reason it rejects const s = []int{1}: the value is not a constant expression. Maps are mutable reference values; making them const would require different semantics and has been discussed for years (for example in issue #22876) without changing the core const rules in Go 1.x.

If you need a mental model: const is for immutable compile-time scalars; a golang map constant in the sense of “never changes” is expressed with var, init, and encapsulation, not the const keyword.


golang global map: package-level var and init

The closest built-in pattern to a “fixed lookup table” is a package-level variable initialized with a composite literal, or assigned in init() when the table depends on other setup.

Run the snippet: the first line prints 42; the second prints true 42 (the comma ok form).

go
package main

import "fmt"

var codeToAnswer = map[string]int{
	"life": 42,
}

func main() {
	fmt.Println(codeToAnswer["life"])
	v, ok := codeToAnswer["life"]
	fmt.Println(ok, v)
}
Output

That map is still mutable inside the same package (codeToAnswer["x"] = 0 is legal). If you want go constant map behavior from other packages, keep the map unexported (codeToAnswer spelled with a lowercase name in real code) and expose only read functions (see below). For more on maps in general, see maps in Go and arrays and structs.


Read-only from outside the package: getters

This pattern does not make the map immutable at runtime, but it prevents other packages from mutating your table because they never receive a map value they can assign into.

go
package config

var labels = map[string]string{
	"en": "Hello",
	"es": "Hola",
}

func Label(lang string) (string, bool) {
	v, ok := labels[lang]
	return v, ok
}

Callers use Label("en") only; they cannot assign through labels[...] from outside the config package.


Returning a map from a function

Some codebases use func Table() map[K]V that returns a new map literal on every call. That gives callers a fresh map they can change without affecting others, at the cost of allocations. A var holding one shared map avoids repeated allocation but shares the same backing map for everyone unless you copy.


golang constant slice (and const strings)

You still cannot write const s = []int{1, 2, 3}. You can keep a const string and convert when needed (the slice is created at run time, not a constant):

go
package main

import "fmt"

const csv = "a,b,c"

func main() {
	parts := []byte(csv) // []byte built at run time from const string
	fmt.Println(len(parts))
}
Output

You should see a small positive length printed (here 5 for a,b,c).

For fixed byte data at package scope, people often use var with a byte slice or populate a slice in init, same as a golang global map.


Summary

Golang const map, go constant map, and golang map const as real const declarations are not valid Go. Use a golang global map with var (and init or sync.Once when initialization is non-trivial), or functions that return maps or values, and use unexported maps with getters when you want other packages to treat the table as read-only. Golang constant slice literals are likewise not const; use var, init, or values derived from const strings or numbers. Clearer pages can help clicks when ranking and snippets already expose you to searchers, but traffic is not guaranteed to jump from edits alone.


References


Frequently Asked Questions

1. Can I declare a const map in Go (golang const map / go const map)?

No. The const keyword only permits constants built from boolean, rune, integer, floating-point, complex, or string values, or constant expressions made from those. Map and slice literals are not constant expressions, so golang constant map and const map golang patterns from other languages do not compile.

2. What is the usual replacement for a golang global map?

Declare a package-level var holding the map, optionally populate it in an init function or sync.Once, and expose read access through functions if you want to discourage other packages from mutating the backing map.

3. Can I have a golang constant slice?

Not as const in the same sense. You can use a package-level var slice, a function that returns a new slice each time, or derive a slice from a const string in code—but the slice value itself is not a compile-time constant.

4. Why does Go disallow constant map and constant slice?

Constants are deeply immutable and resolved at compile time. Maps and slices are reference-like values with runtime identity and mutability; making them const would require new language and runtime rules. The design has stayed with var-based patterns and encapsulation instead.

5. How do I make a map read-only in practice?

Go has no read-only map type. Keep the map unexported in your package and provide getters or methods that only read; callers outside the package then cannot index-assign into your map without going through your API.
Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive …