What is JSON to Go conversion?
JSON to Go conversion generates Go struct definitions from a sample JSON document, giving you typed structs ready for Go’s encoding/json package. Because encoding/json only marshals exported fields, every generated field name is PascalCase and carries a struct tag — for example json:"id" — so it still marshals and unmarshals to the original lowercase JSON key. The generator infers Go types from the data: int64 for whole numbers, float64 for decimals, string for text, bool for true or false, and slices such as []string for arrays, plus pointer types with omitempty for fields that are optional. Even a JSON key that starts with a digit is turned into a legal Go identifier while keeping its original tag. This replaces the tedious job of writing structs by hand to match an API. JSON Formatter Pro generates the code in your browser, so the JSON you paste is never uploaded to a server.
Worked example: JSON → Go
How JSON values map to Go types
| JSON value | Go type |
|---|---|
| string | string |
| integer | int64 |
| fractional number | float64 |
| true / false | bool |
| array | []T (slice) |
| object | a named struct |
| optional / null field | *T with omitempty / any |
| every field | carries a `json:"key"` tag |
Complete Guide to Generating Go Structs from JSON
In Go there is no useful escape hatch when you consume an HTTP API. `encoding/json` unmarshals into a concrete type, which means every endpoint your service talks to needs a `struct`, and nearly every field on that struct needs a `json:"..."` tag — Go only marshals exported (capitalised) fields, and almost no API returns capitalised keys. Writing that out by hand for a response with thirty fields across three levels of nesting is tedious work, and it is the kind of tedious work that fails quietly.
The failure mode is worth naming precisely. If you misspell a tag, omit one on a field whose Go name no longer matches the wire key, or leave a field unexported, json.Unmarshal returns no error at all. It simply leaves that field at its zero value — `""`, `0`, `false`, `nil` — and the rest of your code carries on with data it never actually received. Generating the structs from a real response removes that entire class of bug, because the tag is copied out of the payload instead of retyped from memory.
JSON to Go Struct Generator Pro turns a sample response into ready-to-paste Golang type declarations in milliseconds, with the field columns padded the way gofmt would pad them so the code does not reformat the moment you save it.
How to Convert JSON to Go Structs Online
- Paste Your JSON: Drop a real API response into the left editor, or upload a `.json` file.
- Read the Generated Go: The Go Structs tab renders a `type` declaration for the root object plus one for every nested object it contains, in declaration order.
- Copy Into Your Package: Click Copy, or Download to save a `.go` file, then rename the types to match your domain vocabulary — the `json` tags keep working regardless of what you call them.
A Worked Example: Paginated API Response
Given this trimmed list endpoint, where avatar_url is present on only one of the two records:
{
"request_id": "req_8f21",
"next_page": null,
"results": [
{
"id": 4021,
"user_name": "ada",
"is_active": true,
"balance": 74.25,
"team": { "id": 7, "name": "Platform" }
},
{
"id": 4022,
"user_name": "linus",
"is_active": false,
"balance": 12.5,
"team": { "id": 7, "name": "Platform" },
"avatar_url": "https://cdn.example.com/l.png"
}
]
} the generator produces:
type Root struct {
RequestID string `json:"request_id"`
NextPage any `json:"next_page,omitempty"`
Results []Result `json:"results"`
}
type Result struct {
ID int64 `json:"id"`
UserName string `json:"user_name"`
IsActive bool `json:"is_active"`
Balance float64 `json:"balance"`
Team Team `json:"team"`
AvatarURL *string `json:"avatar_url,omitempty"`
}
type Team struct {
ID int64 `json:"id"`
Name string `json:"name"`
}
Three details are doing real work here. The two records were merged into one Result type rather than two, so an array of a thousand rows still yields a single struct. Because avatar_url was missing from the first record it came out as *string with `,omitempty`, which distinguishes "the API omitted this" from "the API sent an empty string". And request_id became the field RequestID, not RequestId, because Go's initialism convention is applied to the field name while the original key stays safely in the tag.
How JSON Types Map onto Go Types
Every field the generator emits carries a `json:"..."` struct tag containing the original key exactly as it appeared in your payload, so renaming a Go field can never break unmarshalling. JSON strings become `string` and booleans become `bool`, while numbers split in two: a value with no fractional part becomes `int64`, anything else becomes `float64`. `int64` is used rather than `int` because JSON does not specify an integer width and Go's `int` is platform-sized. Nullability is expressed with pointers — a key that was `null` in your sample, or that was missing from some elements of an array of objects, becomes a pointer type such as `*string` or `*Team` and gains `,omitempty`, so a `nil` marshals back out as an absent key instead of a zero value. Slices and `any` are already nil-able, so they take `,omitempty` without a pointer. Nested objects become their own named struct types, and an array of objects is merged into one struct covering the union of the keys observed.
Key Capabilities & Features
🏷️ A json Tag on Every Field
Tags are emitted unconditionally, so an exported Go name never drifts away from the wire key it decodes.
🔢 Distinct `int64` and `float64`
Numbers are not collapsed into one numeric type; whole values become `int64`, fractional values `float64`.
🧬 Ragged Arrays Merged Into One Struct
An array of records yields a single type covering every key seen, with the sometimes-missing ones as `,omitempty` pointers.
🧩 Named Types for Nested Objects
Nested objects become their own types, identical shapes are deduplicated, and a genuine name clash gets a numeric suffix rather than two structs with one name.
📐 gofmt-Aligned, Initialism-Aware
Field columns are padded like gofmt, and segments such as `id`, `url`, `api` and `http` fold to `ID`, `URL`, `API`, `HTTP` so golint stays quiet.
🔒 100% Client-Side Generation
Parsing runs in a Web Worker and code generation runs in the page — your response never crosses the network to be converted.
Generated Code Ends Up in Your Binary — So Read the Generator
A struct generator differs from a formatter in one way that deserves a moment's thought: its output does not stay in the browser tab. It gets pasted into your source tree, reviewed, committed, and compiled into a binary you ship. That raises two questions most online generators simply don't answer — where did the payload go, and what exactly produced the code you're about to commit?
The first answer here is straightforward. Parsing happens in a Web Worker inside your own browser and the struct generation happens on the same page; the JSON is never sent anywhere to be converted. There is no signup, no account, no API key, and no ad-network script on the page. That matters more than usual for this particular conversion, because the payload you paste into a Go struct generator is rarely a public example — it's typically an internal service response whose field names are your data model.
The second answer is that you don't have to take the first one on faith. The whole project is open source, and the code generator is a single readable TypeScript file you can inspect, fork, or self-host: github.com/hashcode-dev/json-formatter-pro. If your team's policy is that generated code has to come from something auditable, that's a box this checks and a hosted black box cannot.
Two honest limitations are worth knowing before the output reaches a code review. A float that happens to be integral in your sample — a `price` of `20` rather than `20.5` — is inferred as `int64`, because browsers' `JSON.parse` genuinely cannot tell `1.0` from `1`; widen those fields by hand. And an array that mixes objects with scalars degrades to `[]any`, since there is no single struct that describes it. Both are visible at a glance in the output, which is rather the point of generating readable code instead of a runtime decoder.
Working across a polyglot stack? The same payload can be run through the JSON to TypeScript interface generator to keep a frontend in sync with these structs, or the JSON to Python dataclass generator for a service on the other side of the queue — all three read the same inferred shape, so the field names and optionality line up. If a response won't parse in the first place, the JSON validator will point at the offending line before you try to generate anything from it.