Use the encoding/json package's MarshalIndent function to format JSON with indentation and newlines, or pipe the output through the jq command-line tool for quick terminal formatting. MarshalIndent is the standard Go approach for programmatic control, while jq is ideal for ad-hoc debugging or shell scripts.
Here is how to pretty-print JSON within a Go program using MarshalIndent:
package main
import (
"encoding/json"
"fmt"
"log"
)
func main() {
data := map[string]interface{}{
"name": "Alice",
"age": 30,
"skills": []string{"Go", "Rust", "Python"},
}
// MarshalIndent takes the data, a prefix (usually empty), and an indent string
prettyJSON, err := json.MarshalIndent(data, "", " ")
if err != nil {
log.Fatal(err)
}
fmt.Println(string(prettyJSON))
}
This outputs:
{
"name": "Alice",
"age": 30,
"skills": [
"Go",
"Rust",
"Python"
]
}
If you are debugging a JSON string already in your code or working in a shell environment, using jq is often faster than writing Go code just for formatting. You can pipe raw JSON directly into it:
echo '{"name":"Bob","active":true}' | jq .
Or if you have a Go binary that outputs raw JSON, you can chain it:
./my-go-app | jq .
When using MarshalIndent, the second argument is a prefix string added to each line (often left empty ""), and the third argument defines the indentation string (e.g., " " for two spaces or "\t" for tabs). If you need to handle json.RawMessage or custom types, ensure your struct tags are set correctly before marshaling, as MarshalIndent respects the same rules as Marshal. For large datasets, be aware that MarshalIndent creates a new byte slice in memory, so it may have a slight performance overhead compared to raw Marshal, but it is negligible for most logging and API response scenarios.