Mahdi.Kh
September 21, 2026
Go, like other programming languages, supports JSON. Here, we get familiar with how to use JSON in Go programs.
JSON (JavaScript Object Notation) is a simple, readable format for exchanging data. In terms of surface structure, data in JSON looks like objects or arrays in JavaScript. Almost all programming languages support JSON, and Go is one of them.
In Go, one way to work with JSON is to use the standard JSON package.
To encode data to JSON, we use the Marshal function. This function has one input parameter and two output parameters, as follows:
If no error occurs, the first output parameter will contain the data in JSON format, and the error value will be nil.
There are some points to note when using this function:
Channels, complex numbers, and functions cannot be converted to JSON.
Cyclic data structures aren't supported. Using cyclic data structures causes this function to go into an infinite loop.
Pointers are encoded as the values they point to. Or, if the pointer is nil, it's encoded as null.
Marshal and Unmarshal functions! That is, their scope must be such that those fields can be accessed.If we use a struct, we can use tags to specify exactly what name each field is encoded (encode or marshal) with in the final JSON:
In the example above, the Name field is converted to JSON with the name first_name. Likewise, the field is encoded with the name . This way, using the tag, we can specify field names exactly.
BodypayloadjsonTo decode JSON, we use the Unmarshal function. This function's parameters are as follows:
This function has two input parameters and one output value. The first input parameter is the data in JSON format, and the second parameter must be a pointer to a variable. This function tries to store the first parameter's JSON-formatted data inside the variable we specified as the second parameter, and if it succeeds, the error value will be nil.
This function is used as follows:
In the example above, if b contains valid JSON that fits into m, then after calling the Unmarshal function, the err value will be nil, and b's data will be stored in the m structure and finally printed to standard output (STDOUT).
Unmarshal Function Identify the Field Matching the Decoded Data?For a JSON key named "Foo", the Unmarshal function searches the fields of the variable we passed as the second parameter in the following order, and if a match is found, it stores the data in that field:
First, it looks for a field that's accessible (in scope) and has a tag named "Foo".
If the above isn't found, it looks for a field that's accessible (in scope) and has the exact name "Foo".
If it still finds nothing, it looks for a field that's accessible (in scope) and whose name matches "Foo" case-insensitively, such as "FOO" or "FoO".
In cases where the JSON structure doesn't match the data type of the variable we want to store the data in, the Unmarshal function only assigns values to the fields it can identify. In the example below, only the Name field in the m variable will be assigned a value, and the Food field is ignored.
This feature is very useful when you want to use only a few specific fields from a large JSON payload in your program. In addition, this behavior shows that in the destination variable, fields that aren't accessible (in scope) aren't affected by the Unmarshal operation, and their values remain unchanged.
If we use a struct, tagging the fields lets us specify which field the data is encoded into and decoded from during Marshal and Unmarshal.
Without knowing the JSON data's structure in advance, we can decode it into a variable of type interface{} using the Unmarshal function.
In the example above, the data is decoded into the f variable like a map whose keys are of type string and values are of type interface{}, something like the example below:
In this case, to access the data, we can use an interface assertion to convert f's type from interface{} to map[string]interface{} and then access the data:
The json package in Go uses the types map[string]interface{} and []interface{} to hold objects and arrays. That is, it's able to decode (unmarshal) any valid JSON data into a variable of type interface{} without issue. In this case, the default types Go considers for JSON data are as follows:
bool for boolean values (true / false)float64 for numbersstring for stringsnil for the null valueUsing the list above, in the previous example we wrote a for loop that iterates over the decoded data and prints each value to standard output (stdout).
In Go, there are certain data types that have a value of nil by default unless we allocate memory for them. For example, the map and slice types, and any pointer data type, fall into this category.
When storing data into a reference data type, the Unmarshal function allocates memory for it if none has been allocated yet.
In the example above, when the Unmarshal function converts the JSON data into the IncomingMessage structure, it only allocates memory for the parts of the structure that actually exist in the JSON data.
This post's content is adapted from the original post about JSON on Go's official website. For more information, you can also read about the json and jsonrpc packages.
Previous part: Defer, Panic, and Recover | Golang basics