New 58+ tools are now available — built to keep your workflow moving.

JSON to Go Struct: Generate Types With JSON Tags

Generate Go structs from JSON free. Get int64, float64, pointers for optional fields, json tags, and nested types using only the standard library.

A Admin 7 min read

To convert JSON to Go, paste a sample into the JSON to Go struct generator, set the package and root type names, and generate. The output is a set of Go structs with exported PascalCase fields, json tags that preserve the original keys, and int64, float64, string, bool, slices and nested structs as the inferred types. It uses only the standard library.

Go's encoding/json needs a destination type, and writing one by hand from a large payload is tedious and easy to get subtly wrong — a missing omitempty, a pointer where it should be a value, a tag that does not match the wire name. Generating from a real response removes most of that work.

What the output looks like

For {"name":"Ada","age":36,"email":null,"tags":["go"],"address":{"city":"London"}}, the generator produces something like:

package main

type Root struct {
    Name    string  `json:"name"`
    Age     int64   `json:"age"`
    Email   *string `json:"email,omitempty"`
    Tags    []string `json:"tags"`
    Address Address `json:"address"`
}

type Address struct {
    City string `json:"city"`
}

The struct is ready to pass to json.Unmarshal, and the tags keep the JSON keys stable even though Go fields must be exported and conventionally PascalCase.

How to generate Go structs from JSON

  1. Open the JSON to Go struct generator.
  2. Paste a representative JSON sample.
  3. Set the root type name. The default is Root.
  4. Set the package name. The default is main.
  5. Press Generate.
  6. Copy the code into a .go file, then run gofmt if your editor does not format on save.

The result reports the number of structs generated, which is a quick check that nested objects became their own types.

Type mapping

JSON value Go type
String string
Integer int64
Decimal float64
Boolean bool
null any (or a pointer when merged with a real type)
Object A generated struct
Array []T
Empty or mixed array []any

int64 is the default for integers because JSON numbers have no width and a value can exceed int32. float64 is the only float type the standard library decodes into without a custom unmarshaler. If your domain guarantees a narrower type, change it after generation and test with real values.

Optional fields, pointers and omitempty

The generator merges samples of the same object shape, including array elements. A key that is missing from some samples or null in some becomes optional, and the generated field gets two adjustments:

  • A pointer type, such as *string, so the zero value can be distinguished from "not present".
  • omitempty in the tag, so marshalling leaves the field out when it is nil.

A purely null field stays any, which already carries nil and needs no pointer. This is the part that matters most in practice: without pointers, an absent number and a real zero look identical after unmarshalling.

If you do not need that distinction, remove the pointer and the omitempty after generating. For a field that should default to a value, keep a value type and handle the default in your code or with a custom unmarshaler.

Field names and tags

Go requires exported fields, so JSON keys are converted to PascalCase: email_address becomes EmailAddress, user-id becomes UserId. The original key is preserved in the tag:

EmailAddress string `json:"email_address"`

That combination is what makes the struct usable: exported names for Go code, exact keys for the wire format. A key starting with a digit is prefixed with N so the field is a legal identifier, and the tag still carries the real name.

Every field gets a tag, not just the renamed ones, so the mapping is explicit and survives a future rename of the Go field.

Root arrays and scalars

A top-level object becomes a struct. A top-level array becomes a slice type:

type Root []Item

A top-level scalar becomes a type alias such as type Root string. Both are valid and easy to change to a named struct if you prefer.

Common problems and fixes

A field is a pointer when it is always present. One merged sample omitted it. Use a uniform sample, or change the field to a value type and drop omitempty.

A field is any when I expected a type. It was null in every sample, or an array mixed incompatible types. Provide a sample with a real value or replace any with the known type.

Numbers lose precision in JavaScript tools but not here. This generator runs in the browser, where JSON parsing uses JavaScript numbers. Integers beyond 2^53 can lose precision before generation. If exact large IDs matter, keep them as strings in the JSON or generate from a smaller sample that preserves them.

The package name is rejected. It is sanitised to a valid identifier, lowercased, with invalid characters replaced. Set a simple name such as main, models or api.

A key became an unexpected field name. Punctuation and acronyms are normalised for a legal Go identifier, with the original key kept in the tag. Rename the field if you prefer.

The JSON will not parse. The input must be strict JSON. Comments, trailing commas and single quotes are rejected; the JSON formatter can locate the syntax error.

Deeply nested payloads stop generating types. Inference is capped at a depth of 24 and 64 structs, and anything beyond becomes any. Generate the upper levels and write the rest by hand.

Tips for better Go structs

  • Use a real response. It contains the nulls and optional fields that determine pointers and omitempty.
  • Include several array elements. The generator merges their shapes, so two or three variants produce a more accurate result than one.
  • Run gofmt. The generated code is valid, but formatting it with the standard tool keeps it consistent with the rest of the package.
  • Keep tags. They are the contract with the JSON producer. Removing them because the field names match today creates a silent break later.
  • Add validation separately. Go structs describe shape; required fields, ranges and formats need explicit checks after unmarshalling.
  • Watch omitempty on zero values. A real 0 or false on a value field with omitempty is omitted when marshalled. That is why optional scalars are pointers here.
  • Generate types for the other side too. The JSON to Rust struct generator and JSON to Zod schema builder cover the same sample in other ecosystems.

Decoding and encoding

The generated structs work with the standard library:

var root Root
if err := json.Unmarshal(data, &root); err != nil {
    return err
}

For encoding, the tags control the output keys, and omitempty drops nil pointers. If you need strict rejection of unknown fields, use a decoder with DisallowUnknownFields() rather than relying on the struct alone. Go ignores unknown keys by default, unlike a strict Zod schema.

Frequently asked questions

Is the JSON to Go generator free?

Yes. There is no account and no charge.

Does my JSON get uploaded?

No. The conversion runs in your browser and the JSON is not stored.

Does it use only the standard library?

Yes. The generated structs work with encoding/json and require no third-party packages.

Why are optional fields pointers?

A pointer distinguishes "missing or null" from a real zero value. Optional fields also get omitempty so they are omitted when marshalling.

Does it generate JSON tags?

Yes. Every field gets a json:"original_key" tag, with ,omitempty added for optional or nullable fields.

Can it handle a top-level array?

Yes. It generates a slice type such as type Root []Item instead of a struct.

Bottom line

A generated Go struct gives you a correct starting point for encoding/json, with the tags and pointer semantics that are easy to forget by hand. Start from a realistic sample, keep the tags, and review pointer fields against what the API actually guarantees. Open the JSON to Go struct generator, and use the JSON to CSV converter if the same data needs to be inspected in a spreadsheet.

Was this helpful? Leave a like or tell us below.

Comments (0)

Be the first to share feedback on this post.

Related posts

View all