JSON Flatten / Unflatten

Flatten nested JSON to dot-notation keys, or unflatten dotted keys back to nested objects. Useful for logging pipelines, Elasticsearch, and config management.

Separator:

Converts nested objects to flat key.path pairs. Arrays become index keys (tags.0, tags.1…).

What is JSON Flattening?

JSON flattening converts a nested JSON object into a flat key-value map where all keys are represented using dot notation. Instead of {"user": {"name": "Ravi"}}, you get {"user.name": "Ravi"}. Unflattening is the reverse — it reconstructs the nested object from dotted keys.

Flattening is used when systems cannot handle nested JSON. Elasticsearch indexes flat field names. Datadog metrics use dot-notation. Environment variable systems like Docker and Kubernetes store config as flat key-value pairs. Relational databases have flat column names. Converting nested JSON to a flat map before passing to these systems avoids mapping errors and simplifies queries.

Flatten vs Unflatten

FlattenUnflatten
InputNested JSON objectFlat JSON with dotted keys
OutputFlat key→value mapNested object
ArraysIndexed as key.0, key.1…Not reconstructed as arrays
Use casesElasticsearch, Datadog, env vars, key-value storesConfig parsing, reconstructing from flat storage

Go — Flatten and Unflatten

go
// Manual flatten in Go
func flatten(obj map[string]interface{}, prefix string) map[string]interface{} {
    result := make(map[string]interface{})
    for k, v := range obj {
        key := k
        if prefix != "" {
            key = prefix + "." + k
        }
        if nested, ok := v.(map[string]interface{}); ok {
            for nk, nv := range flatten(nested, key) {
                result[nk] = nv
            }
        } else {
            result[key] = v
        }
    }
    return result
}

// Or use a library:
// go get github.com/nqd/flat
import "github.com/nqd/flat"

nested := map[string]interface{}{
    "user": map[string]interface{}{
        "name":    "Ravi",
        "address": map[string]interface{}{"city": "Surat"},
    },
}

// Flatten
flattened, err := flat.Flatten(nested, &flat.Options{Delimiter: "."})
// => {"user.name": "Ravi", "user.address.city": "Surat"}

// Unflatten
unflattened, err := flat.Unflatten(flattened, &flat.Options{Delimiter: "."})
// => {"user": {"name": "Ravi", "address": {"city": "Surat"}}}

Python — Flatten and Unflatten

python
def flatten(obj, prefix="", sep="."):
    result = {}
    for k, v in obj.items():
        key = f"{prefix}{sep}{k}" if prefix else k
        if isinstance(v, dict):
            result.update(flatten(v, key, sep))
        elif isinstance(v, list):
            for i, item in enumerate(v):
                if isinstance(item, dict):
                    result.update(flatten(item, f"{key}{sep}{i}", sep))
                else:
                    result[f"{key}{sep}{i}"] = item
        else:
            result[key] = v
    return result

nested = {"user": {"name": "Ravi", "address": {"city": "Surat"}}, "active": True}
flat = flatten(nested)
# => {"user.name": "Ravi", "user.address.city": "Surat", "active": True}

# Or use the flatten package:
# pip install flatten-dict
from flatten_dict import flatten, unflatten
flat2 = flatten(nested, reducer="dot")
nested2 = unflatten(flat2, splitter="dot")

Frequently Asked Questions

Elasticsearch stores nested objects in a flat internal structure and has limited support for deeply nested queries. Flattening JSON before indexing gives predictable field names for queries and aggregations. Tools like Logstash's flatten filter do this automatically for log pipelines.

Arrays are indexed numerically: tags[0] → tags.0, tags[1] → tags.1. Arrays of objects are also flattened with index paths: users.0.name, users.1.name. When unflattening, these become plain objects, not arrays — the tool cannot reconstruct the original array type from the flat representation alone.

Use dot (.) for most use cases — it is the most common convention. Use underscore (_) when your tool uses dots for something else (like nested JSON Schema paths). Use slash (/) for path-style keys in systems like Kubernetes ConfigMaps or Vault secrets.

Top-level arrays are not supported — wrap the array in an object first: {"items": [...]}. This is because flat JSON must be a key→value map, and array indices alone do not carry sufficient structure information for most use cases.

Related Tools