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
jsontextis 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/jsonoffers. - For large files or streamed inputs (e.g., WebSocket JSON messages),
jsontextis 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 ()