Go map to struct: convert map[string]any and round-trip with structs

Golang map to struct and golang convert map to struct: map[string]any (map string interface) to struct via json.Marshal or mapstructure, manual loops, reflect; plus convert struct to map golang with JSON for map to struct golang and go map to struct workflows.

Published

Updated

Read time 5 min read

Reviewed byDeepak Prasad

Go map to struct: convert map[string]any and round-trip with structs

Searches like golang map to struct, golang convert map to struct, map to struct golang, and go map to struct all ask how to fill typed fields from a loose map[string]any (older code often wrote map[string]interface{} — the same idea). Converting map string interface to struct is common after json.Unmarshal into a generic map, or when reading dynamic config. This page shows encoding/json, mapstructure, a small for loop, and a minimal reflect sketch, then briefly covers convert struct to map golang. For map-only JSON paths, see map to JSON in Go and JSON unmarshal in Go.

Tested with Go 1.24 on Linux.


Convert map[string]any to a struct (map to struct golang)

Pick a strategy that matches where the map came from and how strict you want decoding to be.

JSON roundtrip with json.Marshal and json.Unmarshal

If map keys line up with json tags (often lowercase wire names), marshaling to JSON and unmarshaling into the struct is simple and stays in the standard library:

go
package main

import (
	"encoding/json"
	"fmt"
)

type Person struct {
	Name    string `json:"name"`
	Age     int    `json:"age"`
	Address string `json:"address"`
}

func main() {
	m := map[string]any{
		"name":    "Amit Kumar",
		"age":     30,
		"address": "316 Some Main Road, Cruasia",
	}
	b, err := json.Marshal(m)
	if err != nil {
		fmt.Println("marshal:", err)
		return
	}
	var out Person
	if err := json.Unmarshal(b, &out); err != nil {
		fmt.Println("unmarshal:", err)
		return
	}
	fmt.Printf("%+v\n", out)
}
Output

You should see the struct populated with the three fields. This pattern is the default answer for convert map to struct golang when values are JSON-serializable.

mapstructure for nested maps and loose shapes

For golang map string interface to struct when you want direct decode without a JSON hop, or nested map[string]any values mapped into nested structs, mapstructure is a common choice. Run it locally after go get github.com/mitchellh/mapstructure (the in-site Run button cannot fetch this module).

go
package main

import (
	"fmt"

	"github.com/mitchellh/mapstructure"
)

type Person struct {
	Name    string
	Age     int
	Address map[string]string
}

func main() {
	m := map[string]any{
		"Name": "Amit Kumar",
		"Age":  30,
		"Address": map[string]string{
			"street": "316 Some Main Road",
			"city":   "Crusasia",
			"state":  "Karnataka",
			"zip":    "803471",
		},
	}
	var out Person
	if err := mapstructure.Decode(m, &out); err != nil {
		fmt.Println(err)
		return
	}
	fmt.Printf("%+v\n", out)
}

You should see Name, Age, and the nested Address map filled. For stricter decoding (for example surfacing unexpected keys), configure mapstructure.DecoderConfig instead of the one-line Decode.

Manual field copy with a for loop or switch

When the struct is tiny and keys are fixed, explicit conversion avoids magic and keeps dependencies at zero:

go
package main

import "fmt"

type Identity struct {
	Name string
	Age  int
}

func main() {
	m := map[string]any{
		"Name": "Amit Kumar",
		"Age":  30,
	}
	var p Identity
	for k, v := range m {
		switch k {
		case "Name":
			p.Name = v.(string)
		case "Age":
			p.Age = v.(int)
		}
	}
	fmt.Printf("%+v\n", p)
}
Output

You should see {Name:Amit Kumar Age:30}. Type assertions panic if the dynamic type is wrong; production code should use the two-value form or fmt.Sscanf-style parsing depending on the source.

Reflection (advanced, easy to break)

reflect can walk exported struct fields and look up keys by field name. It only works cleanly when map values are already assignable to the field types — otherwise Set panics (for example float64 from JSON into an int field):

go
package main

import (
	"fmt"
	"reflect"
)

type Identity struct {
	Name string
	Age  int
}

func fillFromMap(m map[string]any, dst any) {
	v := reflect.ValueOf(dst).Elem()
	t := v.Type()
	for i := 0; i < t.NumField(); i++ {
		f := t.Field(i)
		if val, ok := m[f.Name]; ok {
			v.Field(i).Set(reflect.ValueOf(val))
		}
	}
}

func main() {
	m := map[string]any{"Name": "Amit Kumar", "Age": 30}
	var p Identity
	fillFromMap(m, &p)
	fmt.Printf("%+v\n", p)
}
Output

Prefer encoding/json or mapstructure once types might not match exactly.


Convert struct to map golang

The symmetric move — struct to loose map — is often done with a JSON hop so json tags become keys:

go
package main

import (
	"encoding/json"
	"fmt"
)

type Person struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
}

func main() {
	p := Person{Name: "Ada", Age: 40}
	b, err := json.Marshal(p)
	if err != nil {
		fmt.Println(err)
		return
	}
	var m map[string]any
	if err := json.Unmarshal(b, &m); err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println(m["name"], m["age"])
}
Output

You should see Ada and 40 (the number may print as a float64 wire form depending on formatting; it is still the right logical value). Building the map by hand is fine when the struct is small and you control the key names.


Summary

For golang map to struct work, json.Marshal followed by json.Unmarshal into a tagged struct is the usual default for convert map to struct golang when keys already look like JSON. golang map string interface to struct scenarios with odd key names or nested dynamic data often fit mapstructure better than hand-rolled reflect. A manual for loop stays readable for very small structs. For convert struct to map golang, marshal the struct to JSON and unmarshal into map[string]any, or assign fields explicitly. Always handle marshal and unmarshal errors in real programs.


References


Frequently Asked Questions

1. What is the usual way to golang map to struct or golang convert map to struct?

Marshal the map to JSON bytes with json.Marshal, then json.Unmarshal into a struct pointer whose json tags match the map keys; check both errors. That covers many map string interface to struct cases from APIs and config blobs.

2. How do I golang map string interface to struct when keys are not JSON names?

Use explicit assignments, github.com/mitchellh/mapstructure with field tags or DecoderConfig hooks, or rename keys in the map before unmarshaling; reflection can map exported field names to keys but is brittle on types.

3. When should I use mapstructure instead of encoding/json?

Prefer mapstructure when you need weak typing, embedded maps and slices decoded into nested structs without a JSON roundtrip, or metadata about unused keys; prefer json when the data is already JSON-shaped and tags are enough.

4. How do I convert struct to map golang?

Marshal the struct to JSON with json.Marshal, then json.Unmarshal into map[string]any, or build a map manually field by field; the JSON path preserves json tag names as map keys.

5. Why does reflect.Value.Set panic when I map to a struct?

Set requires assignable types; a float64 from JSON in your map cannot be assigned to an int field without conversion, so use json or mapstructure for coercion instead of naive reflect.
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 …