Apps Artificial Intelligence CSS DevOps Go JavaScript Laravel Linux MongoDB MySQL PHP Python Rust Svelte Vue

Pretty-Printing JSON in Go with MarshalIndent

2 min read .
Pretty-Printing JSON in Go with MarshalIndent

Compact JSON is efficient for transport, but long documents can be difficult to inspect when everything appears on one line. Go’s standard encoding/json package includes json.MarshalIndent for producing human-readable JSON with line breaks and indentation.

Pretty-printed JSON is useful for debugging, generated configuration, logs intended for people, and command-line output.

1. Use json.MarshalIndent

package main

import (
	"encoding/json"
	"fmt"
)

func main() {
	data := map[string]any{
		"name": "Alice",
		"age":  30,
		"address": map[string]string{
			"street": "123 Main St",
			"city":   "Wonderland",
		},
		"hobbies": []string{"reading", "hiking", "coding"},
	}

	prettyJSON, err := json.MarshalIndent(data, "", "    ")
	if err != nil {
		fmt.Println("Error:", err)
		return
	}

	fmt.Println(string(prettyJSON))
}

MarshalIndent accepts three arguments:

  1. The value to encode.
  2. A prefix added to each output line, often "".
  3. The indentation string, such as two spaces, four spaces, or a tab.

For example, two-space indentation looks like this:

prettyJSON, err := json.MarshalIndent(data, "", "  ")

2. Always Handle Encoding Errors

JSON encoding can fail. Unsupported values include channels, functions, complex numbers, and data containing cycles.

prettyJSON, err := json.MarshalIndent(data, "", "    ")
if err != nil {
    return fmt.Errorf("marshal JSON: %w", err)
}

Returning or wrapping the error is usually more useful in library and application code than merely printing it.

3. Pretty-Print JSON from a File

If a file already contains JSON, you can decode and re-encode it:

fileContent, err := os.ReadFile("data.json")
if err != nil {
    log.Fatalf("read file: %v", err)
}

var data any
if err := json.Unmarshal(fileContent, &data); err != nil {
    log.Fatalf("decode JSON: %v", err)
}

prettyJSON, err := json.MarshalIndent(data, "", "    ")
if err != nil {
    log.Fatalf("encode JSON: %v", err)
}

fmt.Println(string(prettyJSON))

For the specific job of formatting existing JSON bytes, json.Indent can avoid decoding into generic Go values:

var out bytes.Buffer
if err := json.Indent(&out, fileContent, "", "  "); err != nil {
    log.Fatal(err)
}
fmt.Print(out.String())

4. Pretty JSON in an HTTP Response

For debugging or developer-facing endpoints, you can marshal an indented response manually:

func handler(w http.ResponseWriter, r *http.Request) {
	data := map[string]any{
		"status": "success",
		"data": map[string]string{
			"message": "Hello, World!",
		},
	}

	prettyJSON, err := json.MarshalIndent(data, "", "    ")
	if err != nil {
		http.Error(w, "could not encode response", http.StatusInternalServerError)
		return
	}

	w.Header().Set("Content-Type", "application/json")
	w.WriteHeader(http.StatusOK)
	_, _ = w.Write(prettyJSON)
}

For production APIs, compact JSON is usually preferable because indentation increases response size. Pretty output is most useful when humans are expected to inspect the response directly.

Encoder.SetIndent for Streaming Output

When writing directly to an io.Writer, json.Encoder can be more convenient:

encoder := json.NewEncoder(os.Stdout)
encoder.SetIndent("", "  ")

if err := encoder.Encode(data); err != nil {
    log.Fatal(err)
}

This avoids creating the complete encoded byte slice first and automatically writes a trailing newline.

Conclusion

Use json.MarshalIndent when you need an indented JSON byte slice, json.Indent when formatting existing JSON bytes, and json.Encoder.SetIndent when writing JSON directly to a stream. Keep compact output for bandwidth-sensitive APIs, and reserve pretty printing for places where readability matters.

Related Posts

chevron-up