Try it yourself with our free Json To Csv tool — runs entirely in your browser, no signup needed.

How to Convert JSON to CSV in Go

How to Convert JSON to CSV in Go

Converting JSON to CSV is a common task in data processing and analysis. JSON (JavaScript Object Notation) is a popular format for exchanging data between web servers, web applications, and mobile apps, while CSV (Comma Separated Values) is a widely used format for tabular data. In this article, we will explore how to convert JSON to CSV in Go, a modern and efficient programming language.

Quick Example

Here is a minimal example that converts a JSON string to a CSV string:

package main

import (
	"encoding/csv"
	"encoding/json"
	"fmt"
	"strings"
)

func main() {
	jsonStr := `[{"name":"John","age":30},{"name":"Alice","age":25}]`
	var data []map[string]interface{}
	if err := json.Unmarshal([]byte(jsonStr), &data); err != nil {
		fmt.Println(err)
		return
	}

	csvStr := ""
	for _, row := range data {
		csvStr += fmt.Sprintf("%s,%d\n", row["name"], row["age"])
	}
	fmt.Println(csvStr)
}

This code uses the encoding/json package to unmarshal the JSON string into a slice of maps, and then iterates over the slice to construct the CSV string.

Step-by-Step Breakdown

Let's walk through the code line by line:

  1. import "encoding/csv": We import the encoding/csv package, which provides functions for working with CSV data.
  2. import "encoding/json": We import the encoding/json package, which provides functions for working with JSON data.
  3. func main() { ... }: We define the main function, which is the entry point of the program.
  4. jsonStr := [{"name":"John","age":30},{"name":"Alice","age":25}]: We define a JSON string that contains two objects with nameandage` fields.
  5. var data []map[string]interface{}: We define a variable data that will hold the unmarshaled JSON data. The type is a slice of maps, where each map represents an object in the JSON data.
  6. if err := json.Unmarshal([]byte(jsonStr), &data); err != nil { ... }: We use the json.Unmarshal function to unmarshal the JSON string into the data variable. If there is an error, we print it and return.
  7. csvStr := "": We define a variable csvStr that will hold the constructed CSV string.
  8. for _, row := range data { ... }: We iterate over the data slice, and for each row, we construct a CSV string.
  9. csvStr += fmt.Sprintf("%s,%d\n", row["name"], row["age"]): We use the fmt.Sprintf function to construct a CSV string for each row. We use the %s format specifier for the name field and the %d format specifier for the age field.
  10. fmt.Println(csvStr): We print the constructed CSV string.

Handling Edge Cases

Empty/Null Input

If the input JSON string is empty or null, the json.Unmarshal function will return an error. We can handle this case by checking for an error and returning a default value:

if err := json.Unmarshal([]byte(jsonStr), &data); err != nil {
	if err == json.UnmarshalTypeError {
		return "Invalid JSON input"
	}
	return "Error parsing JSON"
}

Invalid Input

If the input JSON string is invalid (e.g., malformed or missing fields), the json.Unmarshal function will return an error. We can handle this case by checking for an error and returning a default value:

if err := json.Unmarshal([]byte(jsonStr), &data); err != nil {
	if err == json.UnmarshalTypeError {
		return "Invalid JSON input"
	}
	return "Error parsing JSON"
}

Large Input

If the input JSON string is very large, we may need to use a streaming approach to avoid running out of memory. We can use the json.NewDecoder function to create a decoder that can read the JSON data in chunks:

dec := json.NewDecoder(strings.NewReader(jsonStr))
for dec.More() {
	var row map[string]interface{}
	if err := dec.Decode(&row); err != nil {
		return "Error parsing JSON"
	}
	// Process the row
}

Unicode/Special Characters

If the input JSON string contains Unicode or special characters, we need to make sure that our CSV output is properly encoded. We can use the strconv.Quote function to quote the CSV values:

csvStr += strconv.Quote(fmt.Sprintf("%s,%d", row["name"], row["age"]))

Common Mistakes

Using encoding/json with interface{}

Using interface{} as the type for the unmarshaled JSON data can lead to runtime errors if the JSON data contains unexpected fields or types. Instead, we should define a struct that matches the expected JSON structure:

type Person struct {
	Name string `json:"name"`
	Age  int    `json:"age"`
}

var data []Person
if err := json.Unmarshal([]byte(jsonStr), &data); err != nil {
	// Handle error
}

Not Handling Errors

Not handling errors properly can lead to unexpected behavior or crashes. We should always check for errors and handle them accordingly:

if err := json.Unmarshal([]byte(jsonStr), &data); err != nil {
	// Handle error
}

Not Using strconv.Quote for CSV Values

Not using strconv.Quote for CSV values can lead to invalid CSV output if the values contain special characters. We should always use strconv.Quote to quote the CSV values:

csvStr += strconv.Quote(fmt.Sprintf("%s,%d", row["name"], row["age"]))

Performance Tips

Use json.NewDecoder for Large Input

Using json.NewDecoder can help improve performance when dealing with large JSON input. This is because json.NewDecoder can read the JSON data in chunks, avoiding the need to load the entire JSON string into memory.

dec := json.NewDecoder(strings.NewReader(jsonStr))
for dec.More() {
	var row map[string]interface{}
	if err := dec.Decode(&row); err != nil {
		return "Error parsing JSON"
	}
	// Process the row
}

Use sync.Pool for Reusable Buffers

Using sync.Pool can help improve performance by reusing buffers instead of allocating new ones. We can use sync.Pool to create a pool of reusable buffers for our CSV output:

var csvBufPool = sync.Pool{
	New: func() interface{} {
		return make([]byte, 1024)
	},
}

func getCSVBuf() []byte {
	return csvBufPool.Get().([]byte)
}

func putCSVBuf(buf []byte) {
	csvBufPool.Put(buf)
}

FAQ

Q: How do I convert a JSON string to a CSV string in Go?

A: You can use the encoding/json package to unmarshal the JSON string into a Go struct, and then use the encoding/csv package to construct the CSV string.

Q: How do I handle large JSON input in Go?

A: You can use the json.NewDecoder function to create a decoder that can read the JSON data in chunks, avoiding the need to load the entire JSON string into memory.

Q: How do I quote CSV values in Go?

A: You can use the strconv.Quote function to quote the CSV values.

Q: How do I improve performance when converting JSON to CSV in Go?

A: You can use json.NewDecoder for large input, and use sync.Pool for reusable buffers.

Q: How do I handle errors when converting JSON to CSV in Go?

A: You should always check for errors and handle them accordingly. You can use error types like json.UnmarshalTypeError to handle specific error cases.

AI agent tools available. The CodeTidy MCP Server gives Claude, Cursor, and other AI agents access to 60+ developer tools. One command: npx @codetidy/mcp