About JSON to Go Struct
Build Go struct definitions with proper JSON tags from any JSON sample. Handles nested objects via inline structs, arrays as slices, and ISO date strings as <code>time.Time</code>. Output is ready to paste into a Go source file — compiles without modification.
Why generate Go structs
Hand-typing a 30-field struct with correct tags is busywork. Tools like mholt/json-to-go solved this years ago for Go developers; this is the same idea, in your browser, with a few modern niceties (time.Time inference, omitempty toggling, named-vs-inline).
What you get
type User struct {
ID int `json:"id"`
Email string `json:"email"`
Name string `json:"name"`
Tags []string `json:"tags,omitempty"`
Address struct {
Street string `json:"street"`
City string `json:"city"`
State string `json:"state"`
Zip string `json:"zip"`
} `json:"address"`
CreatedAt time.Time `json:"created_at"`
}
Common workflows
Type an API client. Generate structs from the API’s sample response, drop into a types.go, use with json.Unmarshal or your client library.
Stub a service handler. Generate request and response structs from a contract example, write the handler against them.
Move from interface{} to typed. A Go service using map[string]interface{} can be partially typed by generating structs from a sample and refactoring incrementally.
Edge cases worth knowing
- Sums / discriminated unions — Go has no native enum, no native sum type. The tool produces a
stringfield; you add a customUnmarshalJSONif you need typed variants. - Numbers without decimal — typed as
int. If you receive1.0as a number, that becomesint; if your data later includes1.5, the generated type won’t fit. Inspect a richer sample. - Empty arrays — typed as
[]interface{}(we cannot infer element type from an empty array). Add a non-empty sample.
For runtime validation alongside the types, pair with a validation library (go-playground/validator).
Frequently asked questions
Inline vs named nested types?
How are JSON tags formatted?
json:"field_name". Field names that differ from Go's PascalCase get an explicit tag. We also emit json:"field,omitempty" for fields that are optional in the input.Snake_case to PascalCase?
created_at becomes CreatedAt with json:"created_at". Standard Go convention.How are dates handled?
time.Time. The json package parses RFC 3339 by default — everything works without custom unmarshaling.What about pointers?
*string for fields that can be null. Without the toggle, optional fields use omitempty + zero values.Generate package boilerplate?
package main line and required imports.Related tools
Last updated: 2025-01-15