go 48 lines · 7 steps

Flattening nested JSON into dotted keys

A recursive walk turns arbitrary JSON into a flat map keyed by dot-separated paths.

Explained by highlit
1package flatten
2 
3import (
4 "encoding/json"
5 "strconv"
6 "strings"
7)
8 
9func Flatten(data []byte) (map[string]any, error) {
10 var root any
11 if err := json.Unmarshal(data, &root); err != nil {
12 return nil, err
13 }
14 
15 out := make(map[string]any)
16 flattenValue("", root, out)
17 return out, nil
18}
19 
20func flattenValue(prefix string, value any, out map[string]any) {
21 switch v := value.(type) {
22 case map[string]any:
23 if len(v) == 0 {
24 out[prefix] = map[string]any{}
25 return
26 }
27 for key, child := range v {
28 flattenValue(join(prefix, key), child, out)
29 }
30 case []any:
31 if len(v) == 0 {
32 out[prefix] = []any{}
33 return
34 }
35 for i, child := range v {
36 flattenValue(join(prefix, strconv.Itoa(i)), child, out)
37 }
38 default:
39 out[prefix] = v
40 }
41}
42 
43func join(prefix, key string) string {
44 if prefix == "" {
45 return key
46 }
47 return strings.Join([]string{prefix, key}, ".")
48}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Recursion mirrors the shape of nested data — one function handles any depth.
  2. 2A type switch on `any` lets you branch on the dynamic runtime type of decoded JSON.
  3. 3Empty containers need explicit handling so they aren't silently lost during flattening.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Flattening nested JSON into dotted keys — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code