JSON to Go Struct
Turn JSON into Go structs with proper tags, naming and type inference.
JSON
Go
About this JSON to Go struct converter
Paste a JSON payload — an API response, a config file, a log line — and get Go struct definitions with the json tags already filled in. Everything runs in your browser, so you can safely paste a production response without it leaving your machine.
Field names follow Go's initialism convention
A key like user_id becomes UserID, not UserId, and api_url becomes APIURL. Go's convention is that initialisms keep a consistent case, and every linter in the ecosystem enforces it. This tool applies the full list — ID, URL, API, HTTP, JSON, UUID, SQL and the rest — so the output does not need renaming before it passes review.
How types are inferred
Numbers are read from the original text rather than a parsed value, which matters more than it sounds. 1.0 and 1 are the same number once JavaScript has parsed them, but the first should be a float64 and the second an int. Values beyond the range of int32 become int64, and an ID too large for int64 becomes json.Number rather than silently losing digits.
Strings in RFC 3339 form become time.Time, which is the format encoding/json can actually decode. A bare date like 2024-01-15 stays a string, because decoding it into a time.Time would fail at runtime.
Arrays are treated as samples, not as one value
Given [{"a":1},{"a":2,"b":"x"}], a naive converter looks at the first element and misses b entirely. This one merges every element: fields that appear in some objects but not others are marked omitempty, a field that is a number in one place and null in another becomes a pointer, and a field that is an integer in one sample and a decimal in another widens to float64. Feed it a whole array of API results and the struct will cover all of them.
What about omitempty and pointers?
omitempty only affects encoding — it omits a field when it holds its zero value. It does nothing when decoding, so it never causes a missing field to fail. The catch is that it cannot distinguish "absent" from "zero": a field tagged omitempty holding 0 or "" disappears on the way out. If that distinction matters, set pointers to Nullable + optional — a *int can be nil for absent and point at 0 for present-and-zero.
Separate types or inline?
Separate types hoists each nested object into its own named type, so you can refer to Address elsewhere in your code, and identical shapes collapse into one declaration. Inline nests the structs anonymously in a single declaration, which keeps everything in one place for a throwaway unmarshal.
My API returned a struct with a hundred fields
Some APIs key an object by record ID — order_48213, user_4821, a UUID — rather than returning an array. Converted literally, that becomes one struct field per record, which decodes the response you pasted and nothing else: the next page of results has different IDs and every field stays empty.
Turn on Detect maps from dynamic keys and an object whose keys all look generated and whose values all share a shape becomes a map[string]Something instead. The tool points this out whenever it sees the pattern, so you are not left wondering why the struct is enormous.
The awkward case is an object that mixes a few fixed keys with many generated ones — a page and a count sitting beside a hundred records. Go cannot express "these named fields, plus any number of others" in a single struct, so there is no tag-driven conversion at all. With map detection on, the tool handles it: the fixed keys stay as ordinary fields, the generated ones collapse into an Entries map, and a matching UnmarshalJSON is written out for you.
It generates MarshalJSON alongside it, which matters more than it looks. Defining only the decoder leaves Go's default encoder in place, and that would write an Entries object nested inside the value instead of splicing the records back in at the top level — so the type would no longer round-trip through itself.
Keys Go cannot express
A JSON key containing a comma, a quote or a symbol such as an emoji cannot be written in a Go struct tag. encoding/json does not report this — it silently ignores the invalid tag and matches on the Go field name instead, so the field never populates. This tool detects those keys, marks them in the output and explains what to do instead, because the failure is otherwise almost impossible to spot.
Is the output gofmt-clean?
Yes. Fields are aligned into columns exactly the way gofmt would, including the rule that a nested struct ends an alignment run while still lining its own name up with the fields above it. Running gofmt on the output changes nothing.