Skip to content

Tools

JSON to Go

Paste JSON, get gofmt-clean structs with json tags — pointers for nullable fields, omitempty on optional ones, time.Time for dates. Runs entirely in your browser.

Nullable:

Generated code

Beta — the generated code is unit- and compile-tested, but inference from one sample can't be perfect; on rare occasions the output may need a tweak. Spot something wrong?Tell me.

What is this tool?

A free JSON-to-Go converter. Paste a JSON document and it generates exported structs for the whole tree, formatted the way gofmt would leave them: aligned fields, proper Go initialisms (ID, URL, notId, Url), json:"…" tags carrying your original keys, and encoding/json-ready types throughout. Warnings name every place your sample was too thin to type — nothing is guessed silently.

Your JSON never leaves the browser. Inference and generation run client-side; the page works offline once loaded.

How to use it

  • Paste JSON on the left — the structs regenerate as you type.
  • Name the root struct; nested structs are named from their keys, singularized inside arrays (users: […]User).
  • Choose how nullable fields are expressed: pointers (default) or bare zero values.
  • Copy or Download the .go file (declared as package models — rename to taste).

Pointers or zero values for nullable fields?

Go has no null for value types, so a JSON field that can be null (or absent) forces a choice:

ModeBehaviorCost
Pointers (default)*string is nil when the key was null or missing — absence is representable and testable.Deref noise, and a nil check you must remember.
Zero valuesstring just becomes "", int64 becomes 0.You can no longer tell "the API sent 0" from "the API sent nothing" — fine for display code, dangerous for business logic.

omitempty and its gotchas

Fields your sample showed as optional (missing from at least one object) get json:"…,omitempty", so marshaling omits them instead of inventing keys. Two things worth knowing:

  • omitempty means "zero value", not "wasn't set". On a bare int64 it also omits a legitimate 0; on a baretime.Time it omits nothing, because a zero struct isn't "empty" to encoding/json. In the default pointer mode optional fields are pointers for exactly this reason — a nil pointer is unambiguously empty. In zero-value mode you're accepting these ambiguities knowingly.
  • Unmarshaling ignores tags you don't have.Unknown incoming keys are silently dropped byencoding/json — if you need strictness, wrap ajson.Decoder withDisallowUnknownFields().

Why int64 and float64

Integer fields are typed int64 rather thanint: JSON IDs routinely exceed 2³¹, and plainint is 32-bit on some platforms — the truncation bug you least want to discover in production. Fields where any sample showed a decimal point become float64, which is exactly what encoding/json decodes into anyway. The distinction comes from the raw token: this tool's parser keeps 1 and 1.0 apart whereJSON.parse would erase it.

time.Time and RFC 3339

String fields become time.Time only when every sample matches ISO 8601 with full date — which is the shapeencoding/json natively unmarshals intotime.Time (RFC 3339, e.g.2026-07-03T10:30:00Z). Date-only strings (2026-07-03) are detected too, butencoding/json won't parse those intotime.Time — if your data uses bare dates, keepDetect dates off for Go or use a custom type wrapping time.Parse("2006-01-02", …).

Struct tags carry your real keys

Whatever the JSON key looked like — created-at,user_id, élan — the Go field is a clean exported identifier and the tag preserves the original spelling, so round-trips are exact:

CreatedAt time.Time `json:"created-at"`
UserID    int64     `json:"user_id"`

The rare key that can't live in a tag (one containing a quote, comma or backtick) is flagged in the warnings instead of being emitted broken.

FAQ

Is it free? Yes — free, no sign-up, no limits.

Is my JSON uploaded anywhere? No — fully client-side, works offline after load; only your last input is kept, in your own browser's local storage.

Why did a field come out any? The sample never showed its type: always null, an empty array, or two values with irreconcilable types. The warnings panel names the exact JSON path. (any is the modern spelling ofinterface — Go 1.18+.)

Does it generate marshal/unmarshal code? It doesn't need to — struct tags are Go's serialization story, and json.Unmarshal(data, &resp) does the rest. Custom UnmarshalJSON methods only earn their keep for exotic shapes.

Can it read a JSON Schema? Not yet — v1 infers from samples; schema input is planned.

Built from scratch for this site in vanilla TypeScript — a pure, unit-tested inference engine with golden-tested emitters and zero runtime dependencies.