jsonflat

Zero-allocation JSON flattening and transformation for Go, driven by a JSON config. Flatten nested documents into flat rows, normalise keys to snake_case, fix misspelt keys, rename, drop, merge and default, whitelist the columns you want, split a batch into records, and route each record to one or more named outputs. Built for high-throughput pipelines that feed columnar storage.

This site documents v0.3.0 (published 2026-10-07). API reference for this version: pkg.go.dev. The Markdown behind these pages, at this version: docs/. For another version, open https://pkg.go.dev/github.com/nayan9229/jsonflat@vX.Y.Z or the docs/ folder of that tag on GitHub.

Install

go get github.com/nayan9229/jsonflat

Go 1.24 or newer. The only dependency is github.com/valyala/fastjson.

Thirty seconds

{
  "rules": [
    {"op": "rename",  "from": "user.id", "to": "uid"},
    {"op": "merge",   "from": ["user.first", "user.last"], "to": "user.name", "sep": " "},
    {"op": "drop",    "path": "debug"},
    {"op": "default", "path": "env", "value": "prod"}
  ]
}
in:  {"user":{"id":7,"first":"Ada","last":"Lovelace"},"tags":["a","b"],"debug":{"x":1}}
out: {"uid":7,"tags.0":"a","tags.1":"b","user.name":"Ada Lovelace","env":"prod"}
t := jsonflat.MustCompile(config)

var out []byte // reuse between calls: that is what keeps Append allocation-free
out, err := t.Append(out[:0], src)

Every config and example on this site is compiled and replayed by docs_test.go in the repository, so what you read is what the code does.

Where to go

Page What it answers
Config reference Every section and field, defaults, the order things happen in, validation errors, troubleshooting.
Recipes Worked examples: cleaning keys, whitelisting columns, exploding a batch, routing to outputs, merging duplicates, per-event tables.
Presets The RudderStack warehouse-schema preset: what it produces, the choices it makes, how to extend it, the Firehose/Glue warning.
Performance Benchmarks with hardware and versions, how to run them, what “zero allocations” and “steady state” mean, memory.
FAQ Why the package has its own JSON escaper, why fastjson, hashes for collisions, streaming, type casting, when a /v2 comes.
Changelog What changed in each version.

The Go API itself (types, functions, runnable examples) is on pkg.go.dev.

Two ideas to hold on to

Source paths and output keys are different things. A source path addresses the input (rule.from, section.from, every source): always . between segments, keys spelt as the producer spells them. An output key is what gets written (rule.to, column.to, alias.to, keys.keep, keys.drop): used exactly as given, after normalisation. With flatten.separator: "_" the same value is user.first on the way in and user_first on the way out.

One document becomes records, a record becomes rows. Without input.explode the document is the one record. Without outputs there is one implicit output, so one record gives one row. With both, a batch of ten events matching two outputs each gives twenty rows, delivered to your callback one by one, each with the output’s name.


jsonflat is MIT licensed. Docs source: docs/.

This site uses Just the Docs, a documentation theme for Jekyll.