Copy or Clone a Map in Go (Shallow vs Deep)

Copy or clone a map in Go: a new map with a range loop duplicates keys but may share slice, map, or pointer values (shallow copy); duplicate nested data with copy(), JSON marshal/unmarshal, or type-specific logic for a deep copy.

Published

Updated

Read time 3 min read

Reviewed byDeepak Prasad

Copy or Clone a Map in Go (Shallow vs Deep)

Assigning one map variable to another does not copy entries; you need a second map and a loop (or serialization) to golang copy map data. A range loop always builds a new top-level map, but values that are reference types may still alias the original unless you copy them deliberately—a shallow versus deep distinction explained below. For map basics, see maps in Go.

Tested with Go 1.24 on Linux.


Shallow copy versus deep copy

A shallow copy is a new map whose values are the same references as the original (slices, nested maps, pointers). A deep copy duplicates those inner structures so mutating the copy does not change the original. Maps themselves are reference types; only the key-value table is new after a typical loop copy.


Copy with a range loop (often shallow)

Values that are independent (int, string, structs of primitives)

go
package main

import "fmt"

func main() {
	orig := map[string]int{"a": 1, "b": 2}
	dup := make(map[string]int, len(orig))
	for k, v := range orig {
		dup[k] = v
	}
	dup["a"] = 99
	fmt.Println(orig["a"], dup["a"])
}
Output

You should see 1 then 99.

Shared inner slices (shallow)

go
package main

import "fmt"

func main() {
	orig := map[string][]int{"nums": {1, 2, 3}}
	dup := make(map[string][]int)
	for k, v := range orig {
		dup[k] = v
	}
	dup["nums"][0] = 99
	fmt.Println(orig["nums"][0])
}
Output

You should see 99 because both maps point at the same backing array.

Duplicating slice values (deep enough for slices)

go
package main

import "fmt"

func main() {
	orig := map[string][]int{"nums": {1, 2, 3}}
	dup := make(map[string][]int)
	for k, v := range orig {
		cp := make([]int, len(v))
		copy(cp, v)
		dup[k] = cp
	}
	dup["nums"][0] = 99
	fmt.Println(orig["nums"][0], dup["nums"][0])
}
Output

You should see 1 and 99.


Deep copy with encoding/json

Use JSON when the value shapes are JSON-serializable and you want a generic deep-ish copy; check errors and expect map[string]any for nested objects after Unmarshal.

go
package main

import (
	"encoding/json"
	"fmt"
)

func main() {
	orig := map[string]any{"key": map[string]int{"one": 1}}
	b, err := json.Marshal(orig)
	if err != nil {
		panic(err)
	}
	var dup map[string]any
	if err := json.Unmarshal(b, &dup); err != nil {
		panic(err)
	}
	inner := dup["key"].(map[string]any)
	inner["one"] = 100
	fmt.Println(orig["key"].(map[string]int)["one"])
	fmt.Println(inner["one"])
}
Output

You should see 1 then 100. More on JSON workflows: JSON unmarshal in Go and map to JSON.


Reflection and third-party helpers

The reflect package can build generic deep copies but is subtle and usually slower than typed code (performance notes). Libraries such as github.com/jinzhu/copier are common for structs and maps in applications that already depend on them—add them in your own go.mod and run locally; they are not Playground-default snippets here.


Summary

To golang copy map data, decide whether shared inner state is acceptable. A range loop plus make duplicates the map header; duplicate slices with copy, nested maps with another loop or JSON, and pointers by allocating new values when you need isolation. JSON marshal and unmarshal is a practical deep copy path for JSON-compatible trees, with explicit error handling and type assertions at the edges.


References


Frequently Asked Questions

1. What is a shallow copy of a map in Go?

A new map whose keys point to the same values as the original; changing a shared slice, inner map, or pointer through one map is visible through the other.

2. How do I deep copy a map[string][]int in Go?

Loop keys and assign a new slice per key, copying elements with the built-in copy function, or serialize with encoding/json if the value shapes are JSON-friendly.

3. Does json.Marshal followed by json.Unmarshal deep copy a map?

It produces new maps and new JSON-compatible values, which is effectively a deep copy for those types, but you must handle errors and type assertions when using map[string]interface{}.

4. Is there a built-in deepCopy for maps in Go?

No. Use explicit logic for your value types, JSON, or a maintained third-party library; reflection-based generic deep copy is possible but easy to get wrong and usually slower.

5. Where can I read more about map mechanics?

See maps in Go for creation, iteration, and zero values before copying.
Tuan Nguyen

Data Scientist

Proficient in Golang, Python, Java, MongoDB, Selenium, Spring Boot, Kubernetes, Scrapy, API development, Docker, Data Scraping, PrimeFaces, Linux, Data Structures, and Data Mining. With expertise …