Practical examples of 3 examples of working with Go maps for real projects

If you’re writing Go in 2024 and still a little shaky on maps, you’re not alone. Developers often want clear, practical examples of 3 examples of working with Go maps that mirror real-world use cases, not toy snippets that never leave a tutorial. In this guide, we’ll walk through several examples of using Go maps in ways that actually show up in production code: counting, grouping, caching, configuration, and more. You’ll see how an example of a Go map can replace clumsy nested loops, how maps interact with JSON, and why the idiomatic “comma ok” pattern matters when you care about performance and correctness. These examples include both beginner-friendly snippets and patterns that experienced Go engineers lean on when building APIs, data pipelines, and microservices. By the end, you’ll have a clear mental model for when maps shine, when they bite, and how to write map-heavy code that stays readable and fast.
Written by
Jamie
Published

Examples of 3 examples of working with Go maps in everyday code

Let’s start with concrete code. Instead of abstract theory, we’ll walk through several examples of 3 examples of working with Go maps that mirror how Go is used in APIs, services, and tooling.

Example of counting and frequency maps

One of the best examples of using Go maps is as a frequency counter. Any time you need to count things—status codes, user actions, log lines—a map is usually the cleanest tool.

package main

import (
    "fmt"
    "strings"
)

func main() {
    text := "go maps are fast and go maps are handy"
    freq := make(map[string]int)

    for _, word := range strings.Fields(text) {
        freq[word]++
    }

    for word, count := range freq {
        fmt.Printf("%q appears %d times\n", word, count)
    }
}

This tiny snippet is one of the classic examples of 3 examples of working with Go maps:

  • You see make(map[string]int) to allocate the map.
  • You see implicit zero values: freq[word] starts at 0, so freq[word]++ just works.
  • You see range over a map to read the data back.

In real services, this pattern scales up to counting API calls per user, tracking feature flags per account, or aggregating metrics before sending them to a time-series database.

Example of safe lookups and the “comma ok” pattern

Another example of Go maps that you will absolutely see in production is the safe lookup pattern, commonly called the “comma ok” idiom.

userRoles := map[string]string{
    "alice": "admin",
    "bob":   "viewer",
}

if role, ok := userRoles["alice"]; ok {
    fmt.Println("Alice role:", role)
}

if _, ok := userRoles["charlie"]; !ok {
    fmt.Println("Charlie not found, using default role")
}

This is one of the best examples of 3 examples of working with Go maps because it teaches three habits you actually need:

  • Never assume a key exists.
  • Distinguish between “key not present” and “key present with zero value.”
  • Keep your code branch-free when you can, but explicit when you must.

You’ll see this pattern everywhere: checking cache hits, verifying configuration keys, or validating request parameters in HTTP handlers.

Examples include nested maps for grouped data

Sometimes an example of a single map is not enough. You want grouping: by region, by category, by user. That is where nested maps come in.

type Sales struct {
    Region string
    Item   string
    Units  int
}

func groupSales(data []Sales) map[string]map[string]int {
    grouped := make(map[string]map[string]int)

    for _, s := range data {
        if _, ok := grouped[s.Region]; !ok {
            grouped[s.Region] = make(map[string]int)
        }
        grouped[s.Region][s.Item] += s.Units
    }

    return grouped
}

This is a realistic example of how analytics dashboards or internal reporting tools might use maps in 2024:

  • Outer key: region ("US", "EU", "APAC").
  • Inner key: item ("laptop", "monitor").
  • Value: aggregated units sold.

These examples of 3 examples of working with Go maps show why maps are so handy for ad‑hoc grouping without bringing in a full database or heavy query engine.

Example of maps as simple in-memory caches

Caching is another area where Go maps shine. For a single-process service, a map plus a mutex can be a surprisingly effective in-memory cache.

package cache

import "sync"

type Cache struct {
    mu sync.RWMutex
    m  map[string][]byte
}

func New() *Cache {
    return &Cache{m: make(map[string][]byte)}
}

func (c *Cache) Get(key string) ([]byte, bool) {
    c.mu.RLock()
    defer c.mu.RUnlock()
    v, ok := c.m[key]
    return v, ok
}

func (c *Cache) Set(key string, value []byte) {
    c.mu.Lock()
    defer c.mu.Unlock()
    c.m[key] = value
}

This is one of the best examples of 3 examples of working with Go maps in real services:

  • A map for fast O(1) lookups.
  • sync.RWMutex for safe concurrent access.
  • A simple API that hides the map from callers.

In 2024, with Go’s sync.Map and third‑party caches available, this pattern is still common for read‑heavy workloads where you want more control than sync.Map gives you.

For more on concurrency and memory behavior, the Go team’s official documentation is still the gold standard: https://go.dev/doc/.

Examples include maps with JSON for APIs

If you’re building APIs, you will eventually mix maps and JSON. Here is an example of using a map for flexible payloads where the schema can change.

package main

import (
    "encoding/json"
    "fmt"
)

type Event struct {
    Type   string                 `json:"type"`
    Fields map[string]interface{} `json:"fields"`
}

func main() {
    payload := []byte(`{
        "type": "signup",
        "fields": {
            "user": "alice",
            "plan": "pro",
            "referrer": "newsletter"
        }
    }`)

    var e Event
    if err := json.Unmarshal(payload, &e); err != nil {
        panic(err)
    }

    fmt.Println("Event type:", e.Type)
    fmt.Println("User:", e.Fields["user"])
}

These examples of 3 examples of working with Go maps are extremely common in logging, analytics, and event-driven systems where you do not want to regenerate structs every time the payload changes slightly.

This pattern also shows up in configuration loaders, where a map[string]any holds arbitrary settings that might be merged from environment variables, files, and defaults.

Example of maps for configuration and feature flags

Configuration is another place where maps quietly run the show. Here is an example of using a map for feature flags keyed by user ID.

type FeatureFlagStore struct {
    flags map[string]bool
}

func NewFeatureFlagStore() *FeatureFlagStore {
    return &FeatureFlagStore{
        flags: map[string]bool{
            "beta-dashboard": true,
            "dark-mode":      false,
        },
    }
}

func (s *FeatureFlagStore) Enabled(flag string) bool {
    return s.flags[flag]
}

In a real system, you might load these flags from a database or a remote config service, but the underlying structure is still a simple map.

These examples include:

  • Mapping feature names to booleans.
  • Mapping service names to timeouts.
  • Mapping environment names ("dev”, “staging”, “prod") to base URLs.

All of these are straightforward examples of 3 examples of working with Go maps that keep configuration code short and readable.

Example of maps for de-duplication and set-like behavior

Go does not have a built-in set type, but a map with empty struct values is the idiomatic substitute.

seen := make(map[string]struct{})

for _, email := range []string{"a@example.com", "b@example.com", "a@example.com"} {
    if _, exists := seen[email]; exists {
        fmt.Println("duplicate:", email)
        continue
    }
    seen[email] = struct{}{}
}

This is a compact example of using a map as a set. The empty struct takes zero bytes of storage, so it is a memory‑friendly pattern.

Real examples include:

  • Removing duplicate user IDs before a batch database write.
  • Tracking which jobs have already been queued.
  • Ensuring you only send one notification per user during a run.

Again, these are real examples of 3 examples of working with Go maps that you will see in production, not just in textbooks.

Maps in Go continue to be heavily optimized by the runtime. As of Go 1.22 and beyond, the team keeps refining memory layout and hash behavior to keep map operations fast for common workloads.

A few practical notes for 2024–2025:

  • Pre-allocate when you can. If you know roughly how many elements you will store, using make(map[K]V, n) can reduce allocations.
  • Avoid using maps as global mutable state. Wrap them in types or pass them as dependencies; this keeps your code testable and easier to reason about.
  • For high‑contention concurrent access, consider sharded maps or specialized libraries instead of a single sync.Mutex around a giant map.

The official Go blog has ongoing discussions about performance and language evolution that are worth following: https://go.dev/blog/.

Deep-dive examples of 3 examples of working with Go maps in services

To tie this together, here are three slightly larger examples of 3 examples of working with Go maps in service-style code.

Example 1: HTTP request metrics by status code

You can track HTTP responses per status code using a map, then export the results to your metrics backend.

package metrics

import "sync"

type HTTPMetrics struct {
    mu      sync.Mutex
    byCode  map[int]int
}

func NewHTTPMetrics() *HTTPMetrics {
    return &HTTPMetrics{byCode: make(map[int]int)}
}

func (m *HTTPMetrics) Record(status int) {
    m.mu.Lock()
    defer m.mu.Unlock()
    m.byCode[status]++
}

func (m *HTTPMetrics) Snapshot() map[int]int {
    m.mu.Lock()
    defer m.mu.Unlock()

    out := make(map[int]int, len(m.byCode))
    for code, count := range m.byCode {
        out[code] = count
    }
    return out
}

This combines several earlier ideas: counting, safe concurrent access, and snapshotting the data for export.

Example 2: In-memory index for fast lookups

Imagine you have a slice of User records loaded from a database. An index map makes lookups instant.

type User struct {
    ID    string
    Email string
}

type UserIndex struct {
    byID    map[string]*User
    byEmail map[string]*User
}

func NewUserIndex(users []User) *UserIndex {
    idx := &UserIndex{
        byID:    make(map[string]*User, len(users)),
        byEmail: make(map[string]*User, len(users)),
    }

    for i := range users {
        u := &users[i]
        idx.byID[u.ID] = u
        idx.byEmail[u.Email] = u
    }

    return idx
}

These examples include multiple maps over the same data for different access patterns, a common trick in services that need to answer queries quickly without hammering the database.

Example 3: Grouping logs by severity

For log processing pipelines, grouping by severity with maps is straightforward.

type LogEntry struct {
    Level   string
    Message string
}

func GroupByLevel(entries []LogEntry) map[string][]LogEntry {
    out := make(map[string][]LogEntry)
    for _, e := range entries {
        out[e.Level] = append(out[e.Level], e)
    }
    return out
}

This last example of grouping shows how maps and slices often pair together: a map for quick access to a bucket, and a slice to hold the ordered entries.

FAQ: examples of Go maps in practice

What are some real examples of using Go maps in production code?

Real examples include:

  • Caches for user profiles or configuration data.
  • Frequency counters for API calls and log lines.
  • In-memory indexes keyed by ID or email.
  • Feature flag stores keyed by flag name.
  • Sets for de-duplicating IDs or emails.

These are all examples of 3 examples of working with Go maps that go far beyond trivial tutorials.

Can you give an example of when not to use a Go map?

Avoid maps when you need ordered data or range queries ("give me all items between A and F"). In those cases, a slice with sorting, or a different data structure, is a better fit. Maps are great for direct lookups; they are not a database.

Are Go maps safe for concurrent use?

Regular maps are not safe for concurrent reads and writes. If multiple goroutines access a map, protect it with a mutex or use sync.Map. The Go documentation explains this clearly in the language spec and concurrency guides at https://go.dev/doc/.

Do Go maps preserve insertion order?

No. The iteration order of a map is intentionally randomized to prevent developers from accidentally relying on it. If you need a stable order, copy the keys into a slice, sort them, and iterate over the slice.

Where can I learn more about Go’s memory model and performance?

The official Go site and educational resources provide solid background on how Go manages memory and concurrency:

These resources pair well with the examples of 3 examples of working with Go maps you saw here, giving you both code patterns and the underlying theory.

Explore More Go Code Snippets

Discover more examples and insights in this category.

View All Go Code Snippets