JSON to Go Struct Converter — Client-Side & Private
Turn any JSON payload into encoding/json-ready Go structs: every field carries its original key as a json tag, snake_case keys become exported PascalCase names, nullable unions become pointers, and ISO-8601 strings map to time.Time. The generator runs in a Web Worker in your browser — zero upload, zero logging.
Zero upload, ever
Inference and code generation run in a Web Worker inside your browser — payloads with PII never touch a server.
Live 300 ms conversion
Output updates as you type, with mixed-array unions, merged objects, and ISO-8601 dates inferred automatically.
gofmt-shaped output
Tab-indented structs with column-aligned tags that drop straight into any package.
Paste JSON to generate a schema
JSON input
Generated schema
Paste JSON on the left — Zod, TypeScript, Pydantic, and Go schemas appear here instantly, generated entirely in your browser.
Technical documentation
From JSON to encoding/json-ready structs
Every nested object becomes its own named struct type, emitted children-first, with each field exported in PascalCase and carrying a json:"original_key" tag that preserves the exact key from your payload — snake_case, kebab-case, or anything else survives the round trip through encoding/json unchanged. Mixed arrays such as [1, "a"] map to []any because Go has no unions, while a nullable value ([1, null]) becomes *float64 so the zero value stays distinguishable from absence.
Optionality is inferred from evidence: a key that is missing from at least one object in an array becomes a pointer with an omitempty tag, letting json.Unmarshal and Marshal round-trip partial API responses faithfully. Empty arrays become []any rather than guessing a wrong concrete element type, and struct fields are column-aligned the way gofmt leaves them.
Type mapping details worth knowing
JSON numbers map to float64 — the type encoding/json unmarshals into any, and the only lossless choice without integer evidence in the sample. Strings matching ISO 8601, including date-only values and timestamps with timezone offsets, map to time.Time with the import "time" block added automatically and only when needed. Booleans map to bool, null-only fields to any, and a root value that is not an object becomes a type alias (type Root = []string).
Field names are derived by splitting keys on separators and camelCase boundaries, so created_at becomes CreatedAt and userID keeps its acronym as UserID — exported, collision-free, and never shadowing Go's keywords. Struct names follow the same rule down the nesting path, keeping deep documents readable and greppable.
Why offline conversion matters for JSON with user data
Go developers converting JSON to structs are usually integrating a real third-party API or internal service — and the example payloads are production captures full of names, emails, addresses, and session tokens. That is personally identifiable information that privacy regulations and corporate security policies prohibit sharing with arbitrary third parties, which is exactly what a server-backed online converter asks you to do: upload your users' data to an unknown server with unknown logs and retention.
This page is a static export with no backend of any kind. The struct generator is pure TypeScript running in a Web Worker inside your browser tab — parsing never touches the network, and a watchdog terminates any conversion that exceeds three seconds so oversized pastes cannot freeze the UI. It works offline once loaded, making it safe for production payloads on corporate machines and in air-gapped environments.
Using the generated structs
Drop the output into a .go file (it arrives with a package declaration) and unmarshal with json.Unmarshal(body, &root) — field names, tags, pointers, and time.Time values align with what encoding/json expects, so no post-processing is needed. Nullable pointers marshal back as null rather than zero values, and omitempty fields drop cleanly when absent.
If your API sends integers, float64 still decodes them exactly (Go's float64 is lossless for JSON integers up to 2^53) — and when you want int64 fields for IDs, a one-line type change is all it takes since the tags already carry the correct keys. For API clients beyond encoding/json, the same struct shapes transfer to jsoncodegen tools or generated OpenAPI types unchanged.
Frequently asked questions
Is my JSON uploaded when converting to Go structs?
No. The page is static and the generator runs locally in a Web Worker — payloads containing emails, names, or auth tokens are never transmitted, stored, or logged by any server.
Are the original JSON keys preserved in the struct tags?
Yes. Every field carries a json:"..." tag with the exact key from your payload, so snake_case, kebab-case, or otherwise unusual keys round-trip through encoding/json exactly as they arrived.
Why do some fields become pointers?
Fields that are null somewhere in the sample, or missing from some objects in an array, become pointers (*T) — often with omitempty — so you can distinguish a zero value from an absent one when unmarshalling partial API responses.
How are ISO-8601 date strings typed?
They map to time.Time, and the import "time" block is added automatically. encoding/json parses RFC 3339 timestamps straight into time.Time values, which ISO 8601 with timezone offsets satisfies.
Why does a mixed array like [1, "a"] become []any?
Go has no union types, so any is the honest representation. A nullable numeric array ([1, null]) is more specific and becomes []*float64, keeping nil-able elements round-trippable.
Can I convert a JSON array at the root?
Yes. A root array of objects generates the item struct plus a type alias (type Root = []RootItem), so you can unmarshal directly into a slice while keeping the item type exported and reusable.