JSON to Go structs
Paste a JSON response and the Go structs for it appear as you type, lined up the way gofmt writes them. Nothing you paste leaves this tab.
How to use it#
- Paste a JSON sample into the box above, such as a response from the API you are calling.
- Name the top-level struct.
- Leave omitempty on to mark keys that some objects in an array leave out, or turn it off.
- Copy the Go from beside the result, or download it as a .go file.
How the Go types are chosen#
Text becomes string and true or false becomes bool. A number becomes int when every value seen in that place is a whole number that fits in 32 bits, int64 when one is larger, json.Number when one is too big even for int64, and float64 as soon as one has a fractional part. A price written as 12.0 counts as whole, since the zero is lost when the JSON is read, so include one real price such as 12.5 or change the type by hand. An object becomes a struct of its own named after its key, an array becomes a slice, and an object with no keys becomes map[string]any.
Field names are exported, because encoding/json only fills exported fields, and they follow the Go convention for initialisms: user_id becomes UserID and api_url becomes APIURL, which is what the linters ask for. Each field carries a json tag with the original key, so the name you see in Go never has to match the JSON.
A place that holds two kinds of value, or that the sample says nothing about, such as an empty array, becomes any. That still decodes, and you can narrow it once you know what the API really sends.
Null, missing keys, and pointers#
In Go a string that was never set and a string set to "" look the same. When a value is null in the sample, the field becomes a pointer, such as *string, so that null decodes to nil and stays distinguishable from an empty value. Slices and maps are left alone, since a nil slice already stands for null.
omitempty works in the other direction, when Go writes JSON. A field tagged with it is left out when it holds its zero value. It is added to keys that some objects in an array lack, since those are the fields the API treats as optional. It has no effect on reading, and on a nested struct it does nothing at all, so use a pointer there, or the omitzero option added in Go 1.24, if the object must be left out.
What a sample cannot tell you#
The structs describe the JSON you pasted, not every response the API could send. A field that was null everywhere in the sample is typed as any, and a key present in every object is not marked optional even if the API sometimes drops it. The more varied the sample, the better the structs, so paste an array of several real records if you have them. A date such as 2026-09-28T10:00:00Z comes out as string too, since JSON has no date type. Change the field to time.Time, which encoding/json reads from text in that RFC 3339 form.
When the top level is an array or a single value, the output starts with a named type for it, such as type Root []RootItem, so json.Unmarshal can decode straight into it. For the same model as TypeScript interfaces, use JSON to TypeScript, and for C# classes, JSON to C#.
Frequently asked questions#
What does omitempty do?
#
It tells encoding/json to leave a field out when Go writes JSON and the field holds its zero value: an empty string, a zero, false, or nil. It changes nothing when reading. Here it is added to keys that some objects in an array lack, because those are the ones the API treats as optional. Turn it off to write every field every time.
Why is a field a pointer?
#
Because the sample had null there. A plain int decodes null as 0, which cannot be told apart from a real zero, while *int decodes it as nil. If the value is never null in practice, change the pointer back to the plain type.
Why is it UserID and not UserId?
#
Go writes initialisms such as ID, URL, API, and HTTP in capitals throughout, and the standard linters flag the mixed case forms. The json tag keeps the original key, so the JSON still reads and writes as user_id.
Does it write a package line?
#
No. The output is the type declarations only, so it can go into whichever package needs them. Add package and, if you use the types elsewhere, keep the struct names exported as they are.
Is the JSON I paste sent anywhere?
#
No. It is parsed and converted in this browser tab as you type, so a response with real customer data in it stays on your machine.