JSON to Go
Turn a JSON sample into Go structs with json tags, correct optional/pointer handling and no signup.
How fields and types are inferred
Each nested object becomes its own exported struct, named after the key that holds it
(address → Address). Keys inside an array are named from the
singular form, so projects: [{…}, {…}] produces a single
Project struct rather than one type per element.
| JSON value | Go type | Why |
|---|---|---|
| whole number | int64 | JSON has no integer width; 64 bits covers everything a JavaScript parser can produce. |
| decimal number | float64 | encoding/json decodes unspecified numbers as float64. |
true / false | bool | — |
| string | string | — |
| array | []T | Every element is inspected and the types are merged. |
| object | a named struct | Hoisted out of the parent so it can be reused. |
null | any, or *T | Switch Nullable scalars as pointers off to get any everywhere. |
Optional fields become omitempty
A key that appears in one element of an array but not in its siblings is optional.
Optional and nullable fields get ,omitempty on the tag, which is what lets Go
round-trip a payload where a field is simply absent:
type Project struct {
ID int64 `json:"id"`
Title string `json:"title"`
Archived bool `json:"archived,omitempty"`
} Uncheck Add omitempty to optional fields if you want every key marshalled unconditionally — for instance when an API expects the field to always be present.
Nullable values and pointers
JSON has three states for a field: present with a value, present as null, and
absent. A plain string can only represent the first two of these ambiguously.
With Nullable scalars as pointers enabled, a value that was null
in the sample becomes *string, so a nil pointer tells you the API
explicitly said null. Slices and structs skip the pointer, since a
nil slice already carries the same meaning.
Using the generated structs
var payload Root
if err := json.Unmarshal(body, &payload); err != nil {
log.Fatal(err)
}
fmt.Println(payload.Address.City) Edge cases worth knowing
- Method names beat tags on export. A key has to survive as an exported Go
identifier, so it is converted to PascalCase:
isActivebecomesIsActive, and well-known initialisms are preserved (id→ID,url→URL). The original spelling always lives on in thejsontag, so marshalling stays exact. - Keys starting with a digit (
"2fa") cannot be Go identifiers. They get a leading underscore and become unexported — the tag still works, but you may want to rename them by hand. - Mixed arrays.
[1, "two"]has no single Go type; the element becomesany. - An empty array carries no element type, so it becomes
[]any. Uncheck Use any instead of interface{} if your module targets Go 1.17 or earlier.
FAQ
Why int64 and not int?
JSON numbers carry no width, and int is 32-bit on some platforms. int64 matches what encoding/json would produce with UseNumber off, so it round-trips without surprises.
Are the structs gofmt-compatible?
Yes — field names, types and tags are column-aligned the way gofmt aligns them, so a paste and save will not reflow the file.
Is my JSON uploaded?
No. The generator is plain JavaScript running in this tab. Nothing is sent anywhere.
Only one sample is available — what if the API returns more shapes?
Paste an array containing a few representative elements. Optionality is inferred across siblings, so the more variety you give it, the more accurate the omitempty set becomes.