JSONをGoに変換
JSON to Go generates structs from a sample document in your browser. Every field is exported and carries an explicit json tag, because encoding/json silently ignores unexported fields — a lowercase field name is the single most common reason a generated struct marshals to an empty object.
このツールの画面は英語表記です。
Empty JSON input (truncated document)
^
以下の解説は英語のみでご覧いただけます。
How does JSON to Go Struct work?
Three decisions make a generated Go struct either correct or quietly broken, and all three are about what encoding/json does at runtime rather than about how the code looks.
Every field is exported, and tagged
Go only marshals exported fields. A struct with a field called id produces {} from json.Marshal and leaves id at zero after json.Unmarshal, with no error either way. So every name is capitalised and given an explicit json:"…" tag carrying the original key. Initialisms follow Go's own style guide: user_id becomes UserID, not UserId, and api_url becomes APIURL.
Optional fields are pointers
A plain string cannot hold JSON null, and it cannot tell an absent key from an empty one — both arrive as "". A plain int cannot distinguish a missing count from a count of zero. Optional and nullable fields therefore become pointers, which is the only construction in Go that keeps the distinction. Slices, maps and interface{} are already nilable, so they are left alone rather than given a pointless second indirection.
Integers that int cannot hold become int64
int is 32-bit on some platforms. A snowflake ID or a millisecond timestamp overflows it, and the resulting bug appears only on the platform where it is narrow. Values beyond 2,147,483,647 are emitted as int64.
Unions are interface{}, because Go has no sum type
An array holding both strings and numbers has no Go type that describes it. Generators that invent one produce code that fails to unmarshal; interface{} is the honest answer, and the place to fix it is the API, not the struct.
The output is already gofmt-aligned
Names, types, tags and trailing comments are padded to matching columns. Without that, the first gofmt in CI produces a diff on a file nobody edited.
Sample
[
{ "user_id": 900719925474099, "api_url": "https://x.dev" },
{ "user_id": 12, "api_url": "https://y.dev", "note": "hi" }
]Generated
type User struct {
UserID int64 `json:"user_id"`
APIURL string `json:"api_url"`
Note *string `json:"note,omitempty"` // optional
}What options and edge cases does JSON to Go Struct support?
| Parameter | Type | Default | Behaviour & edge cases |
|---|---|---|---|
| Package | identifier | main | The package clause at the top of the file. Set it to whatever the destination file lives in — models, api, internal/store. |
| pointers | boolean | on | Optional and nullable fields become *T, so an absent key is distinguishable from the zero value. Turning this off makes the struct simpler and makes missing data invisible. |
| omitempty | boolean | on | Adds ,omitempty to optional fields so they disappear when marshalled back. Note that omitempty also drops a genuine empty string or zero, which is exactly why the pointer matters. |
| json.Number | boolean | off | Emits json.Number for non-integers instead of float64, preserving the literal digits. Worth it for money or for IDs that arrive as unquoted numbers beyond float64's exact range. |
| string | Go type | string | Detected formats (uuid, date-time, email, uri) are noted in a comment rather than mapped to a type, because encoding/json will not parse a timestamp into time.Time without a custom unmarshaller. |
| integer | Go type | int / int64 | int by default; int64 when any sample exceeds 2,147,483,647. A truncated ID is a bug that only shows up in production. |
| number | Go type | float64 | Any value with a fractional part. If an integer and a float appear in the same field across records, the field becomes float64. |
| nested object | Go type | *Named | Promoted to its own struct and referenced by pointer, which avoids copying on assignment and lets the field be nil. Identical shapes share one struct. |
Frequently asked questions
Why is every field capitalised when my JSON keys are lowercase?
Because encoding/json only sees exported fields, and export in Go means an uppercase first letter. A lowercase field is skipped by both Marshal and Unmarshal with no error, so the struct compiles, runs, and does nothing. The json tag carries the original key, so the wire format is unchanged.
Do I need the pointers?
You need them wherever absent and zero mean different things. A *int that is nil means the key was missing; an int that is 0 could be either. For a field like retry_count or discount that distinction usually matters. For a field you know is always present it is noise, and turning pointers off is reasonable.
Why is my timestamp a string instead of time.Time?
Because encoding/json will not parse an arbitrary timestamp into time.Time on its own — it only handles RFC 3339, and only if the field is declared as time.Time, which then fails hard on any other format. Generating time.Time from a sample would produce a struct that panics on the first record that formats a date differently. The detected format is noted in a comment so you can make that choice deliberately.
What is interface{} doing in my struct?
A field held genuinely different types across your samples — a string in one record, an object in another — and Go has no type that expresses that. The alternatives are a custom UnmarshalJSON, a json.RawMessage you decode later, or fixing the API. A generated union type would simply fail to unmarshal.
Will gofmt change the output?
It should not. Field names, types, tags and trailing comments are padded to matching columns, which is what gofmt does to a struct. If you find a case where gofmt still produces a diff, that is a bug worth reporting rather than a style preference.
Is my JSON uploaded?
No. The parse, the type inference and the rendering all run in your browser. Nothing is sent anywhere, which matters because the samples people paste into a struct generator are usually real API responses from a system they are integrating against.