JSON tools

JSON to Go Struct Converter

Paste JSON and get idiomatic Go structs: exported names with Go initialisms, a json tag on every field, and pointers where a value can be missing.

  • Free foreverNo trial, no paywall, no usage limits.
  • No sign-upOpen the page and start. We never ask for an email to use a tool.
  • PrivateEverything runs in your browser. Your input is never uploaded or stored on our servers.
  • Works offlineOnce the page has loaded, the tool keeps working without a connection.

Go options

Every option has a tooltip. Your choices are remembered on this device; your JSON never is.
Reset options to defaults
Name of the top-level type. If your JSON is an array, this names each item. Nested types are named after their keys.
The package clause at the top of the file.
Fixed 64-bit width: safe for IDs and timestamps on every platform.Platform-sized int: idiomatic for counts and indexes.
Add ,omitempty to fields that were null or missing, so Marshal leaves them out instead of writing zero values.
Use *T for fields that can be null or missing, so you can tell absent from zero (nil vs 0 or "").
Type RFC 3339 date-times as time.Time; encoding/json parses them for you.

JSON sample

Paste a real response. Arrays are treated as samples: keys missing from some items become optional, null values nullable.
Clear

Go models

CopyDownload models.go
Paste JSON or load the example. Code is generated in your browser as you type.

Need this built into your own API or pipeline? Talk to our team

Quick answer

Go decodes JSON into structs whose exported fields carry json tags naming the original keys. Paste a sample into Playxoft's free JSON to Go converter to generate them: names follow Go conventions, so user_id becomes UserID, whole numbers become int64, RFC 3339 dates become time.Time, and fields that can be null or missing get pointers and omitempty. Then decode with json.Unmarshal into your root struct.

  • Go initialisms in names
  • json tags on every field
  • omitempty and pointers
  • int64 or int
  • time.Time for dates
  • gofmt-aligned output
  • Download models.go

How to use the JSON to Go

  1. 1Paste JSON into JSON sample and set the Root type name.
  2. 2Set the Package name and choose int64 or int for whole numbers.
  3. 3Toggle omitempty, Pointers for optional and time.Time to match your codebase.
  4. 4Copy the structs or download models.go.
  5. 5Decode with json.Unmarshal(body, &data) or json.NewDecoder(r.Body).Decode(&data).

How do Go struct tags map JSON keys?

encoding/json only sees exported fields, the ones whose names start with a capital letter, so a JSON key like user_id needs a Go field with a tag naming the original key:

type User struct {
	ID        int64     `json:"id"`
	Email     *string   `json:"email,omitempty"`
	CreatedAt time.Time `json:"created_at"`
	Password  string    `json:"-"`            // never encoded or decoded
	Count     int64     `json:"count,string"` // a number sent as a JSON string
}

Without a tag, Unmarshal still matches keys to field names case-insensitively, so Email would catch email, but user_id would never reach UserID. The generator writes a tag for every field, so the mapping is explicit and survives renames.

How are JSON types mapped to Go?

JSON in your sampleGo type
Stringstring
RFC 3339 date-timetime.Time
Whole numberint64 (or int)
Whole number beyond int64json.Number
Decimal numberfloat64
Booleanbool
Array[]T
ObjectA named struct
Empty or ID-keyed objectmap[string]T
Mixed types, or only nullany

int64 is the default because IDs and Unix timestamps outgrow 32 bits, and int is only 64 bits wide on 64-bit platforms. Nested objects become separate named structs rather than anonymous inline ones, so you can reuse them, write methods on them and refer to them in tests.

When should I use pointers and omitempty?

Go has no "missing" state: a decoded int64 that wasn't in the JSON is just 0, indistinguishable from a real zero. When the difference matters, use a pointer, where nil means absent or null:

Field typeKey missingValue nullValue 0
int64000
*int64nilnilPointer to 0

omitempty controls encoding: the field is left out of Marshal output when it holds a zero value, meaning 0, "", false, nil, or an empty slice or map. It never omits a struct value; Go 1.24 added the omitzero option for that. The generator adds pointers and omitempty only to fields that were missing or null in your samples and keeps required fields as plain values.

How do I decode JSON safely in Go?

json.Unmarshal is fine for small payloads. For request bodies, a Decoder gives you more control:

dec := json.NewDecoder(r.Body)
dec.DisallowUnknownFields() // reject keys the struct doesn't declare
var in CreateUser
if err := dec.Decode(&in); err != nil {
	var syntaxErr *json.SyntaxError
	if errors.As(err, &syntaxErr) {
		log.Printf("bad JSON at byte %d", syntaxErr.Offset)
	}
	http.Error(w, err.Error(), http.StatusBadRequest)
	return
}

Decoding into map[string]any turns every number into float64, which loses precision above 2^53. Call dec.UseNumber() to get json.Number values instead, or decode into typed structs like the ones generated here.

Why are field names like UserID and not UserId?

Go style keeps initialisms in a consistent case: ID, URL, HTTP, API, JSON, UUID. That is why user_id becomes UserID and avatarUrl becomes AvatarURL, which is what linters such as staticcheck expect. Keys that start with a digit get a Field prefix (2fa becomes Field2fa), since Go identifiers can't start with one.

The output is aligned the way gofmt aligns it, so it drops into a file without a reformatting diff.

Since Go 1.27, encoding/json runs on the new encoding/json/v2 engine with unchanged v1 behavior (opt out with GOEXPERIMENT=nojsonv2). The v2 API reads the same json tags, but by default it matches names case-sensitively, rejects duplicate keys and invalid UTF-8, and its omitempty omits empty JSON values, so use omitzero for Go zero values.

Frequently asked questions

The fields are probably unexported (lowercase), so encoding/json can't set them, or the keys don't match the field names or tags. Check the error from Unmarshal too: a type mismatch stops decoding that field.
Use int64 for IDs, timestamps and anything that might exceed 32 bits, so the code behaves the same on every platform. int is fine for counts and indexes. Switch with the Integer type option.
They become float64, which can't hold integers above 2^53 exactly. Call UseNumber on a json.Decoder to receive json.Number values instead, or decode into structs with int64 fields.
time.Time only decodes RFC 3339 strings. For other formats, define your own type that wraps time.Time and implement UnmarshalJSON with time.Parse and your layout. The generator uses time.Time only when every sample was RFC 3339.
No. omitempty never omits struct values. Use a pointer to the struct, which is nil when absent, or the omitzero tag option added in Go 1.24.
Decode into a slice of the item struct: var users []User, then json.Unmarshal(body, &users). When your sample is an array, the generator also writes a named slice type such as UserList that you can decode into directly.

Last updated by the Playxoft engineering team.

From the engineers who built this tool

Fighting messy data every day?

When payloads, schemas and integrations keep breaking, the fix is usually upstream. We design typed APIs and backends that stay clean as you grow. Tell us what you are building and we will suggest the simplest architecture that fits.