Go JSON Parsing: encoding/json vs jsontext, and Why You Might Want Both
When working with JSON in Go, most developers naturally reach for the standard library's encoding/json
package. It’s convenient, reliable, and has been the default for years. But if you’ve ever found yourself needing more control, better performance for large payloads, or streaming JSON processing, you might want to look into jsontext
.
This article will help you understand the difference between encoding/json
and golang.org/x/text/json/jsontext
, why you might use both, and how they can complement each other.
🧰 What Is encoding/json
?
The encoding/json
package is the standard Go library for working with JSON. It provides high-level APIs to marshal and unmarshal Go structs.
import "encoding/json"
type User struct {
Name string `json:"name"`
Age int `json:"age"`
}
jsonStr := `{"name": "Sony", "age": 30}`
var u User
_ = json.Unmarshal([]byte(jsonStr), &u)
✅ Pros
- Easy to use.
- Supports struct tags and reflection.
- Ideal for APIs and typical request/response flows.
❌ Cons
- Doesn’t work well with huge or streaming JSON.
- Not suitable for partial or dynamic parsing.
- Less efficient for token-level manipulation.
🔬 Enter jsontext
from golang.org/x/text/json/jsontext
jsontext
is a low-level JSON tokenizer and parser. It’s not part of the standard library, but maintained by the Go team in the golang.org/x/text
modules.
You can install it using:
go get golang.org/x/text/json/jsontext
Why Use It?
Instead of decoding whole structs, you can read JSON token-by-token (objects, arrays, strings, numbers) — which is ideal for large files, logs, or streams.
dec := jsontext.NewDecoder(strings.NewReader(`{"name": "Sony", "age": 30}`))
for {
tok, err := dec.ReadToken()
if err != nil {
break
}
fmt.Printf("Token: %#v\n", tok)
}
✅ Pros
- Works well for huge JSON files or streamed data.
- Gives fine-grained control.
- Allows partial parsing — skip what you don’t need.
❌ Cons
- Requires more manual work.
- Doesn’t map JSON to structs automatically.
- Not for casual or simple use cases.
🧠 When Should You Use Each?
Scenario | Use encoding/json |
Use jsontext |
---|---|---|
Parsing API responses | ✅ Easy and clean | ❌ Overkill |
Reading large logs | ❌ Memory-heavy | ✅ Efficient |
Selective JSON field parsing | ❌ Not possible | ✅ Perfect |
Streaming JSON from stdin or socket | ❌ Complex | ✅ Designed for it |
Token inspection or filtering | ❌ Limited | ✅ Excellent |
🤝 Combine the Best of Both Worlds
You don’t have to choose only one. You can use jsontext
to navigate or isolate part of a JSON payload, and then use encoding/json
to map that part to a struct.
Here’s a real-world example: imagine this JSON input:
{
"meta": { "version": "1.0", "timestamp": "2025-04-13T12:00:00Z" },
"data": { "name": "Sony", "age": 30 }
}
We want to ignore the "meta"
section, and decode only "data"
.
🧪 Code Example
import (
"bytes"
"encoding/json"
"fmt"
"strings"
"golang.org/x/text/json/jsontext"
)
type Data struct {
Name string `json:"name"`
Age int `json:"age"`
}
func main() {
input := `{
"meta": { "version": "1.0", "timestamp": "2025-04-13T12:00:00Z" },
"data": { "name": "Sony", "age": 30 }
}`
dec := jsontext.NewDecoder(strings.NewReader(input))
var foundDataRaw json.RawMessage
var currentKey string
for {
tok, err := dec.ReadToken()
if err != nil {
break
}
if key, ok := tok.(string); ok {
currentKey = key
continue
}
if currentKey == "data" {
var buf bytes.Buffer
_ = dec.ReadValue(&buf)
foundDataRaw = buf.Bytes()
break
}
}
var d Data
_ = json.Unmarshal(foundDataRaw, &d)
fmt.Printf("Name: %s, Age: %d\n", d.Name, d.Age)
}
✅ Output:
Name: Sony, Age: 30
This lets you skip irrelevant fields and only decode what matters. Perfect for performance-critical or structured log processing.
⚠️ Things to Keep in Mind
jsontext
is part ofgolang.org/x
, not the standard library — it may evolve independently.- It’s not a replacement for
encoding/json
, but a power tool when you need more than whatencoding/json
offers. - For large files or streamed inputs (e.g., WebSocket JSON messages),
jsontext
is a solid choice.
🧾 Finally
Use encoding/json
for convenience, and use jsontext
when you need control. And if you’re building robust services that consume third-party JSON data — or handling massive logs — you’ll love combining both.
If you want to process JSON intelligently, without loading the entire blob into memory, or just need a laser-focused way to extract fields, jsontext
will make your tooling smarter and faster.
Comments ()