Question

Can You Declare a Constant Map in Go? Understanding Constants and Maps in Golang

Question

I am trying to declare a constant in Go, but the compiler reports an error.

This is my code:

const myMap = map[int]string{
    1: "one",
    2: "two",
    3: "three",
}

The error message is:

map[int]string{…} (value of type map[int]string) is not constant

Why does this happen in Go, and what is the correct way to define a map that should not be changed?

Short Answer

By the end of this page, you will understand why map values cannot be declared as const in Go, what kinds of values can be constants, and the usual alternatives developers use when they want read-only map-like data.

Concept

In Go, const is only for values that the compiler can fully determine at compile time. These are simple, immutable values such as:

  • numbers
  • booleans
  • strings
  • certain constant expressions built from them

A map is different. A map is a runtime data structure with internal state. It is a reference type, which means it points to underlying data managed by the Go runtime. Because of that, a map is not a constant value and cannot be declared with const.

Your code fails because this:

map[int]string{
    1: "one",
    2: "two",
    3: "three",
}

creates a map value at runtime, not a compile-time constant.

In real Go programs, when you want fixed lookup data, you usually do one of these:

  • declare a package-level var
  • avoid exporting the map directly
  • expose helper functions for safe access
  • use a switch if the mapping is small and truly fixed

This matters because Go separates constant values from mutable runtime data structures. Understanding that difference helps you choose the correct tool and avoid compiler errors.

Mental Model

Think of a Go constant like a number printed in a textbook: it never changes, and the compiler knows it in advance.

A map is more like a whiteboard dictionary in an office:

  • it exists at runtime
  • it can be updated
  • it has internal structure
  • people can write and erase entries

Even if you intend not to modify the whiteboard, it is still a whiteboard, not printed text. That is why Go does not let you call it a constant.

Take Quiz

Syntax and Examples

In Go, constants and maps use different declarations.

Valid constants

const pi = 3.14
const appName = "My App"
const maxRetries = 3

These work because they are compile-time constant values.

Invalid constant map

const myMap = map[int]string{
    1: "one",
    2: "two",
}

This does not compile because a map is not a constant.

Correct way: use var

var myMap = map[int]string{
    1: "one",
    2: "two",
    3: "three",
}

This creates a normal map variable.

Safer pattern: keep the map unexported and provide a function

package main

import "fmt"

var numberWords = map[int]string{
    1: "one",
    2: "two",
    3: "three",
}

func NumberWord(n int) (string, bool) {
    value, ok := numberWords[n]
    return value, ok
}

func main() {
    word, ok := NumberWord(2)
    if ok {
        fmt.Println(word)
    }
}

This is useful because other code cannot directly modify the map if you do not expose it.

Alternative for small fixed mappings: use switch

func NumberWord(n int) string {
    switch n {
    case 1:
        return "one"
    case 2:
        return "two"
    case 3:
        return "three"
    default:
        return ""
    }
}

For a small, fixed set of values, this can behave more like a true immutable lookup.

Step by Step Execution

Consider this example:

package main

import "fmt"

var numberWords = map[int]string{
    1: "one",
    2: "two",
    3: "three",
}

func main() {
    value, ok := numberWords[2]
    fmt.Println(value, ok)
}

Here is what happens step by step:

  1. The program starts.
  2. The package-level variable numberWords is created.
  3. Go allocates and initializes the map with three key-value pairs.
  4. In main, the expression numberWords[2] looks up key 2.
  5. Because key 2 exists, Go returns:
    • "two" as the value
    • true for ok
  6. fmt.Println(value, ok) prints:
two true

Now compare that with a constant:

const x = 10

For x, the compiler already knows the value at compile time. No runtime map allocation is needed. That is the key difference.

Real World Use Cases

Developers often need lookup data that should stay stable during program execution.

Common examples

  • HTTP status code descriptions
  • country code to country name mappings
  • file extension to MIME type lookups
  • internal configuration labels
  • enum-like display names

Example: status text lookup

var statusText = map[int]string{
    200: "OK",
    404: "Not Found",
    500: "Internal Server Error",
}

Example: role labels

var roleLabels = map[string]string{
    "admin":  "Administrator",
    "editor": "Editor",
    "user":   "User",
}

In these cases, the map is usually declared once and treated as read-only by convention, even though it is technically mutable.

Take Quiz

Real Codebase Usage

In real Go codebases, developers rarely need a true constant map. Instead, they use patterns that make mutation unlikely or controlled.

Common patterns

1. Package-level unexported variable

var statusNames = map[int]string{
    1: "pending",
    2: "approved",
    3: "rejected",
}

Because the variable starts with a lowercase letter, it is not exported from the package.

2. Accessor function

func StatusName(code int) (string, bool) {
    s, ok := statusNames[code]
    return s, ok
}

This gives controlled read access.

3. Defensive copy when returning maps

If you must return a map, return a copy so callers cannot change the original.

func StatusNames() map[int]string {
    copyMap := make(map[int]string, len(statusNames))
    for k, v := range statusNames {
        copyMap[k] = v
    }
    return copyMap
}

4. switch for small fixed sets

For a tiny fixed mapping, switch can be simpler and impossible to mutate externally.

5. Validation and guard clauses

A common usage pattern is validating input against a known set of values.

func IsValidRole(role string) bool {
    _, ok := roleLabels[role]
    return ok
}

These patterns are more idiomatic than trying to force a map into const.

Common Mistakes

Mistake 1: Trying to use const with a map

Broken code:

const myMap = map[int]string{
    1: "one",
}

Why it fails:

  • maps are runtime values
  • const only supports compile-time constants

Fix:

var myMap = map[int]string{
    1: "one",
}

Mistake 2: Assuming var means the data must change

Some beginners think var means “this should be modified.” That is not true.

var config = map[string]string{
    "env": "prod",
}

This is still fine even if you never change it.

Mistake 3: Exposing the map directly

package settings

var Labels = map[string]string{
    "a": "Alpha",
}

Problem:

  • other packages can modify Labels

Safer approach:

package settings

var labels = map[string]string{
    "a": "Alpha",
}

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

Mistake 4: Forgetting that map lookups may fail

fmt.Println(numberWords[99])

This prints the zero value ("") if the key is missing.

Better:

value, ok := numberWords[99]
if !ok {
    fmt.Println("not found")
}

Mistake 5: Thinking Go has built-in immutable maps

Go does not have a built-in readonly map or const map feature. Immutability is usually enforced by design and package boundaries, not by the map type itself.

Comparisons

Constants vs variables in Go

Featureconstvar
Known at compile timeYesNot necessarily
Can hold numbers, strings, booleansYesYes
Can hold mapsNoYes
Can be changed laterNoYes
Requires runtime allocationNoSometimes

Map vs switch for fixed lookups

OptionBest forMutableEasy to extend
maplarger or data-driven lookupsYesYes
switchsmall fixed casesNo external mutationLess convenient for many values

Exported map vs accessor function

ApproachAdvantageDrawback
Exported mapSimple accessAny caller can modify it
Accessor functionBetter control and safetySlightly more code
Return a copyPrevents external mutation of originalExtra allocation and copying
Take Quiz

Cheat Sheet

// Valid constants
const name = "Go"
const max = 10
const enabled = true

// Invalid: maps cannot be constants
// const labels = map[int]string{1: "one"}

// Use var instead
var labels = map[int]string{
    1: "one",
    2: "two",
}

Key rules

  • const is only for compile-time constant values.
  • Maps are runtime reference types.
  • A map cannot be declared with const.
  • Use var for maps.
  • If you want read-only behavior, hide the map and expose functions.

Safe access pattern

value, ok := labels[1]
if ok {
    fmt.Println(value)
}

Read-only style pattern

var labels = map[int]string{1: "one"}

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

When to use switch

Use switch instead of a map when:

  • there are only a few fixed cases
  • you want logic that cannot be mutated
  • the mapping is simple and static

FAQ

Why can't a map be a constant in Go?

Because a map is a runtime data structure, not a compile-time constant value.

What types can be const in Go?

Basic constant-compatible values such as numbers, strings, booleans, and constant expressions based on them.

How do I make a read-only map in Go?

Go has no built-in read-only map. The usual approach is to keep the map private and provide functions to read from it.

Should I use var even if the map never changes?

Yes. That is normal in Go. A map that you intend not to modify is still declared with var.

Is switch better than a map for fixed values?

Sometimes. If the mapping is very small and truly fixed, switch can be simpler and safer.

Can other packages modify my map?

Yes, if you export the map directly. To prevent that, keep it unexported and expose accessor functions instead.

Does returning a map from a function make it safe?

Not if you return the original map. Callers can still modify it. Return a copy if you need isolation.

Take Quiz

Mini Project

Description

Build a small number-to-word lookup utility in Go. This project demonstrates the correct way to store fixed lookup data using a package-level map and a helper function instead of trying to use const with a map.

Goal

Create a Go program that looks up number names safely and reports whether a number exists in the mapping.

Requirements

  • Declare a map using var, not const
  • Store at least five number-to-word pairs
  • Write a function that returns both the word and a boolean indicating whether the key exists
  • In main, test the function with one existing key and one missing key
Take Quiz

Keep learning

Related questions

View more