Skip to main content
  1. Tutorials/

📎 Convert JSON to CSV in Go

·5 mins

To convert JSON data to a CSV file in Go, you need to create a new struct for JSON data, then decode the JSON file into an array of these structs, and finally save the data from this array as subsequent rows of the CSV file. The two main packages necessary to do this are encoding/json to decode the JSON data with the json.Decoder and encoding/csv to write the output CSV data using csv.Writer.

See also our examples of how to convert CSV to JSON and how to read CSV file or how to write data to a CSV file in Go.

In the example below, we use the data.json file:

[
    {
        "vegetable": "carrot",
        "fruit": "banana",
        "rank": 1
    },
    {
        "vegetable": "potato",
        "fruit": "strawberry",
        "rank": 2
    }
]

Code #

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package main

import (
    "encoding/csv"
    "encoding/json"
    "fmt"
    "log"
    "os"
)

type FruitAndVegetableRank struct {
    // 1. Create a new struct for storing read JSON objects
    Vegetable string `json:"vegetable"`
    Fruit     string `json:"fruit"`
    Rank      int64  `json:"rank"`
}

func convertJSONToCSV(source, destination string) error {
    // 2. Read the JSON file into the struct array
    sourceFile, err := os.Open(source)
    if err != nil {
        return err
    }
    // remember to close the file at the end of the function
    defer sourceFile.Close()

    var ranking []FruitAndVegetableRank
    if err := json.NewDecoder(sourceFile).Decode(&ranking); err != nil {
        return err
    }

    // 3. Create a new file to store CSV data
    outputFile, err := os.Create(destination)
    if err != nil {
        return err
    }
    defer outputFile.Close()

    // 4. Write the header of the CSV file and the successive rows by iterating through the JSON struct array
    writer := csv.NewWriter(outputFile)
    defer writer.Flush()

    header := []string{"vegetable", "fruit", "rank"}
    if err := writer.Write(header); err != nil {
        return err
    }

    for _, r := range ranking {
        var csvRow []string
        csvRow = append(csvRow, r.Vegetable, r.Fruit, fmt.Sprint(r.Rank))
        if err := writer.Write(csvRow); err != nil {
            return err
        }
    }
    return nil
}

func main() {
    if err := convertJSONToCSV("data.json", "data.csv"); err != nil {
        log.Fatal(err)
    }
}

The contents of the output data.csv file:

vegetable,fruit,rank
carrot,banana,1
potato,strawberry,2

How it works #

Create a new struct for storing read JSON objects #

11
12
13
14
15
16
type FruitAndVegetableRank struct {
    // 1. Create a new struct for storing read JSON objects
    Vegetable string `json:"vegetable"`
    Fruit     string `json:"fruit"`
    Rank      int64  `json:"rank"`
}

The first step of JSON to CSV conversion is to load the JSON data to a Go struct. So, we define a proper type, with the fields matching the data in the file and annotate them with JSON struct field tags to enable JSON decoding into that struct.

Read the JSON file into the struct array #

19
20
21
22
23
24
25
26
27
28
29
30
// 2. Read the JSON file into the struct array
sourceFile, err := os.Open(source)
if err != nil {
    return err
}
// remember to close the file at the end of the function
defer sourceFile.Close()

var ranking []FruitAndVegetableRank
if err := json.NewDecoder(sourceFile).Decode(&ranking); err != nil {
    return err
}

We can start processing our JSON file. We open it (remember to close the file to release resources back to the system, for example, using defer keyword) and then create a new json.Decoder with this file as an argument. Since json.NewDecoder(r io.Reader) requires io.Reader, we do not need to read the content of the file beforehand. If we were to use the json.Unmarshal() function, it would be necessary. With Decode() method, we read the JSON file and convert it to the slice of FruitAndVegetableRank objects.

Create a new file to store CSV data #

32
33
34
35
36
37
// 3. Create a new file to store CSV data
outputFile, err := os.Create(destination)
if err != nil {
    return err
}
defer outputFile.Close()

The CSV data will be saved to a file, so in this step, we create a new destination file in a pretty standard way.

Write the header of the CSV file and the successive rows by iterating through the JSON struct array #

39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
// 4. Write the header of the CSV file and the successive rows by iterating through the JSON struct array
writer := csv.NewWriter(outputFile)
defer writer.Flush()

header := []string{"vegetable", "fruit", "rank"}
if err := writer.Write(header); err != nil {
    return err
}

for _, r := range ranking {
    var csvRow []string
    csvRow = append(csvRow, r.Vegetable, r.Fruit, fmt.Sprint(r.Rank))
    if err := writer.Write(csvRow); err != nil {
        return err
    }
}

As the last step, we create a new csv.Writer that writes the data in CSV format to the output file. Remember to call writer.Flush to ensure that all the buffered content is written before the function finishes. The writing process consists of iterating through the array of FruitAndVegetableRank objects and making a CSV row for each of them. Then, This row is saved using writer.Write() method. In the example, we also wrote the header row as the first line of the file.