Question
How can I pretty-print JSON output in Go?
I want a simple way to format JSON so it is easier to read in Go. Specifically, I would like to:
- pretty-print the result of
json.Marshal - format an existing JSON string so it becomes indented and readable
What is the standard way to do this in Go?
Short Answer
By the end of this page, you will understand how to format JSON in Go using the standard library. You will learn when to use json.MarshalIndent for Go values, when to use json.Indent for existing JSON text, and how to avoid common mistakes when working with indented output.
Concept
JSON can be stored or transmitted in two common forms:
- compact JSON: no extra spaces or line breaks
- pretty-printed JSON: includes indentation and new lines for readability
In Go, the encoding/json package gives you built-in tools for both cases.
Two common situations
-
You have a Go value such as a struct, map, or slice, and want JSON output.
- Use
json.MarshalIndent
- Use
-
You already have JSON text in a string or byte slice and want to reformat it.
- Use
json.Indent
- Use
Why this matters
Pretty-printing JSON is useful when:
- debugging API responses
- logging structured data
- saving readable configuration files
- inspecting test output
- making JSON easier for humans to review
Pretty-printing does not change the actual data. It only changes how the JSON text is laid out with spaces and new lines.
Go keeps this simple by separating:
- encoding Go data into JSON with
MarshalandMarshalIndent - reformatting existing JSON text with
Indent
That distinction is important because the right function depends on what you start with.
Mental Model
Think of JSON formatting like writing an address.
- Compact JSON is like writing the whole address on one line.
- Pretty-printed JSON is like splitting it across multiple lines so it is easier to scan.
The information is the same either way.
In Go:
json.MarshalIndentis like taking your data and writing it neatly from the start.json.Indentis like taking a messy block of text and reformatting it cleanly.
Syntax and Examples
Pretty-print a Go value with json.MarshalIndent
Use this when you have a Go value such as a struct or map.
package main
import (
"encoding/json"
"fmt"
)
type User struct {
Name string `json:"name"`
Age int `json:"age"`
Admin bool `json:"admin"`
}
func main() {
user := User{Name: "Ava", Age: 28, Admin: true}
data, err := json.MarshalIndent(user, "", " ")
if err != nil {
fmt.Println("error:", err)
return
}
fmt.Println(string(data))
}
Output:
{
"name": "Ava",
"age": 28,
"admin"
Step by Step Execution
Consider this example:
package main
import (
"encoding/json"
"fmt"
)
func main() {
m := map[string]any{
"name": "Lina",
"age": 31,
}
data, err := json.MarshalIndent(m, "", " ")
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(data))
}
Step by step
-
m := map[string]any{...}- A Go map is created with two key-value pairs.
-
json.MarshalIndent(m, "", " ")- Go converts the map into JSON.
""means no extra prefix is added to each line." "means each nested level uses two spaces.
-
The result is stored in
data
Real World Use Cases
Common uses for pretty-printed JSON
Debugging API responses
When calling an API, compact JSON can be hard to read in logs. Pretty-printing helps you inspect nested objects and arrays.
Writing readable config files
If your Go program saves settings as JSON, indented output makes the file easier for humans to edit.
Test output
When a test fails, pretty JSON is much easier to compare than one long line.
Logging structured data during development
During local development, developers often print indented JSON to understand what data is flowing through the program.
Data inspection tools
CLI tools built in Go may fetch or generate JSON and present a readable version to the user.
Real Codebase Usage
In real Go projects, developers usually combine pretty-printing with a few common patterns.
1. Pretty-print only in development or debugging
Indented JSON is larger than compact JSON, so many applications avoid it in production responses unless readability matters.
if debug {
data, _ := json.MarshalIndent(payload, "", " ")
fmt.Println(string(data))
}
2. Return early on JSON errors
Error handling is usually done immediately.
data, err := json.MarshalIndent(payload, "", " ")
if err != nil {
return err
}
3. Validate incoming JSON before formatting it
If JSON comes from outside your program, it may be invalid.
var out bytes.Buffer
if err := json.Indent(&out, input, "", " "); err != nil {
return fmt.Errorf("invalid JSON: %w", err)
}
4. Use helper functions
Teams often wrap formatting in a reusable function.
(, ) {
data, err := json.MarshalIndent(v, , )
err != {
, err
}
(data),
}
Common Mistakes
1. Using json.Marshal when you actually want indented output
Broken example:
data, err := json.Marshal(user)
fmt.Println(string(data))
This works, but the output is compact, not pretty.
Correct version:
data, err := json.MarshalIndent(user, "", " ")
fmt.Println(string(data))
2. Trying to pass a JSON string directly to json.MarshalIndent
Broken example:
raw := `{"name":"Ava"}`
data, _ := json.MarshalIndent(raw, "", " ")
fmt.Println(string(data))
This encodes the string itself as JSON, which is not the same as reformatting the JSON text.
Correct approach:
var out bytes.Buffer
err := json.Indent(&out, []byte(raw), "", " ")
fmt.Println(out.String())
3. Forgetting to handle errors
Broken example:
Comparisons
| Task | Best Function | Input | Output |
|---|---|---|---|
| Encode a Go struct/map/slice as compact JSON | json.Marshal | Go value | []byte |
| Encode a Go struct/map/slice as readable JSON | json.MarshalIndent | Go value | []byte |
| Reformat existing JSON text | json.Indent | JSON []byte + writer | formatted text in buffer |
json.Marshal vs json.MarshalIndent
Cheat Sheet
Quick reference
Pretty-print a Go value
data, err := json.MarshalIndent(v, "", " ")
Pretty-print existing JSON text
var out bytes.Buffer
err := json.Indent(&out, input, "", " ")
formatted := out.String()
Signatures
json.MarshalIndent(v any, prefix, indent string) ([]byte, error)
json.Indent(dst *bytes.Buffer, src []byte, prefix, indent string) error
Use this when
json.MarshalIndent: you have a Go valuejson.Indent: you already have JSON text
Common indent values
"" // no prefix
" " // two spaces
"\t" // tab
Important rules
- Pretty-printing changes formatting, not data
FAQ
How do I pretty-print JSON from a struct in Go?
Use json.MarshalIndent:
data, err := json.MarshalIndent(v, "", " ")
How do I format an existing JSON string in Go?
Use json.Indent with a bytes.Buffer:
var out bytes.Buffer
err := json.Indent(&out, []byte(raw), "", " ")
What is the difference between json.Marshal and json.MarshalIndent in Go?
json.Marshal creates compact JSON. json.MarshalIndent creates indented, human-readable JSON.
Does pretty-printing JSON change the data?
No. It only changes whitespace such as spaces and line breaks.
Why does json.MarshalIndent on a string not format my JSON text?
Because it treats the string as a plain Go string value and encodes that string into JSON. It does not parse and reformat the JSON inside the string.
Can json.Indent fail?
Mini Project
Description
Build a small Go program that prints a compact JSON payload in a readable format. This project demonstrates both common pretty-printing workflows: creating readable JSON from a Go struct and reformatting an existing JSON string.
Goal
Create a program that pretty-prints JSON from both a Go value and an existing raw JSON string.
Requirements
- Define a struct representing a simple API response or user record.
- Use
json.MarshalIndentto print the struct as indented JSON. - Store a compact JSON string and reformat it with
json.Indent. - Print both formatted results to the console.
- Handle any errors returned by JSON functions.
Keep learning
Related questions
Blank Identifier Imports in Go: What `_` Means in an Import Statement
Learn what `_` means in a Go import, why blank identifier imports run package init code, and when to use them safely.
Check if a Value Exists in a Slice in Go
Learn how to check whether a value exists in a slice in Go, and why Go has no Python-style `in` operator for arrays or slices.
Concatenating Slices in Go with append
Learn how to concatenate two slices in Go using append and the ... operator, with examples, pitfalls, and practical usage.