Generate Go structs from JSON
Go developers often want one thing from JSON generation: clean structs with the right field names and json tags. JSON All-in-One can infer Go structs from local JSON and give you a starting point for encoding/json work.
Review the generated structs alongside your decoder. Numeric types, nulls, date/time values, and mixed-value fields may need explicit handling before the data is ready for your application.
Use events that expose tags and pointers
This illustrative event response uses snake_case keys, nested objects, arrays, nulls, and a large integer. It is shaped to explain exported field names, JSON tags, optional nested structs, and integer policy.
For Go, include at least two records if the API returns arrays. A field that is null or absent in one record should be reviewed before you rely on a non-pointer generated field.
[
{
"event_id": "evt_1001",
"sequence": 9007199254740993,
"kind": "deploy.started",
"received_at": "2026-09-04T07:12:00Z",
"actor": { "user_id": 10, "display_name": "Rae" },
"labels": ["prod", "manual"]
},
{
"event_id": "evt_1002",
"sequence": 9007199254740994,
"kind": "deploy.finished",
"received_at": "2026-09-04T07:14:30Z",
"actor": null,
"labels": []
}
]Review structs and JSON tags
Generated Go structs should use exported field names so other packages can read them, while preserving original JSON keys in tags such as json:"event_id". That is the main value of a JSON-to-Go struct workflow: the code becomes idiomatic without losing the wire format.
After generation, check the top of each Go file before compiling. If a single-file output places an import below a type declaration, move the import block to the top of the file or switch to the multi-file output and compile again.
package events
type GeneratedRootItemActor struct {
DisplayName string `json:"display_name"`
UserId int64 `json:"user_id"`
}
type GeneratedRootItem struct {
Actor *GeneratedRootItemActor `json:"actor"`
EventId string `json:"event_id"`
Kind string `json:"kind"`
Labels []string `json:"labels"`
ReceivedAt string `json:"received_at"`
Sequence int64 `json:"sequence"`
}
type GeneratedRoot = []GeneratedRootItemVerify decoding, not just syntax
Decode the sample with encoding/json and check the resulting field values. This catches mismatched tags, unexpected nulls, and numeric types that cannot hold the input.
If you choose native numbers, know why. If the JSON contains identifiers beyond JavaScript-safe range but within Go int64, decoding may still be fine for Go, while downstream JavaScript or spreadsheets could be unsafe. If you choose *big.Int or *big.Float, verify the decoder behavior separately.
var events GeneratedRoot
if err := json.Unmarshal([]byte(input), &events); err != nil {
log.Fatal(err)
}
for _, event := range events {
fmt.Println(event.EventId, event.Actor != nil)
}Go policy choices
Go supports native or string date/time, native int64, *big.Int, or string integer policy, native float64 or *big.Float decimal policy, and native any or string for unknown JSON values. Those choices affect imports and decoding expectations.
Use time.Time only when the generated output and parsing format match the actual JSON. A timestamp string in JSON is not magically a time.Time unless the decoder can parse it in the expected format.
| Option area | Go choices | What to verify |
|---|---|---|
| Package | Go package identifier | Name compiles in a small module. |
| Null nested object | Pointer or value shape | Decode fixture with null. |
| Integer | int64, *big.Int, or string | Imports and decoder behavior. |
| Date/time | string or time.Time | Timestamp parse expectations. |
Workflow checklist
- Open a representative array or object in JSON All-in-One.
- Select Go and set the package identifier.
- Review generated names, tags, pointers, slices, and primitive policies.
- Prefer multi-file output if single-file output places imports below declarations.
- Run a decode check against the exact fixture before relying on the model.
Limitations to keep visible
Generated Go structs do not replace API contracts or validation. They also do not automatically choose business-safe numeric representations. If an API sometimes sends a number and sometimes a string, the model should be reviewed as a union or custom type problem rather than pasted blindly.
Do not turn this workflow into a benchmark claim. The job is model generation and integration review, not speed testing.