JSON to Go Struct Converter

Paste JSON and get Go struct definitions with encoding/json tags, ready for json.Unmarshal. The sample is analysed in your browser and never uploaded.

JSON → Go

Input

Settings

History

Load from URL

Structs for encoding/json

Decoding JSON in Go means declaring a struct for every object, with an exported field and a json:"…" tag per key. For a large API response that is a lot of typing, and a single wrong tag silently leaves a field empty. Generating the structs from a real payload gets the shape and the tags right first time. Paste a response body, a config file or a webhook sample.

Type mapping

  • JSON objects become struct types; nested objects are separate named structs (Address, Order), referenced by value.
  • Field names are exported PascalCase versions of the keys, with the usual Go initialisms (id becomes ID, created-at becomes CreatedAt). The tag always carries the original key.
  • Whole numbers become int64 and anything with a fraction or exponent becomes float64. A value written 1.0 counts as a float, so sample data with .0 decimals is typed correctly.
  • Strings and booleans map to string and bool; arrays map to slices such as []string or []Order.
  • Objects inside an array are merged into one struct. A key missing from some items becomes a pointer with omitempty (*string json:“email,omitempty”``), and a key that is sometimes null becomes a pointer, so “absent” and “zero” can be told apart.
  • A key that is only ever null, or an empty array’s element, becomes interface{}.
  • An array mixing types, such as [1, "a"], gets a small union struct with UnmarshalJSON and MarshalJSON methods, plus the helper functions they need.

A top-level array produces type Root []RootElement. The output also includes an UnmarshalRoot function (named after your root type) and a Marshal method for convenience.

Options

Root type name (default Root) is the name of the top-level struct, converted to PascalCase. Package (default main) sets the package clause, so the file can go straight into, say, internal/api with api as the package. An invalid package name falls back to main.

Edge cases handled for you

Some JSON keys cannot be expressed naively in a struct tag. A key that is literally - would make encoding/json skip the field, so it is written as json:"-,". A key containing a backtick is written with an interpreted string literal instead of a raw one. Keys whose name starts with a non-Latin letter (名前) get an X prefix so the field is exported and actually decoded. Empty keys and keys containing a comma cannot be named in a json tag at all; a warning tells you which field will not decode.

Integers beyond 2^53 in the sample are typed as float64 with a warning — switch them to int64, json.Number or string if you need exact values. Dates stay string; change them to time.Time if the format is RFC 3339. The result is gofmt-formatted and is generated entirely in your browser. Pair it with cURL to Go to get the request code too.

Examples

API response with nested data

Generates Root, Address and Order structs in package billing, with id as int64 and score and total as float64.

Input
{
  "id": 1042,
  "name": "Aisha Tan",
  "score": 98.5,
  "tags": ["admin", "beta"],
  "address": { "city": "Singapore", "postcode": "018956" },
  "orders": [
    { "id": "ord_1", "total": 129.9, "paid": true },
    { "id": "ord_2", "total": 79, "paid": false }
  ]
}
Output
// To parse and unparse this JSON data, add this code to your project and do:
//
//    root, err := UnmarshalRoot(bytes)
//    bytes, err = root.Marshal()

package billing

import "encoding/json"

func UnmarshalRoot(data []byte) (Root, error) {
	var r Root
	err := json.Unmarshal(data, &r)
	return r, err
}

func (r *Root) Marshal() ([]byte, error) {
	return json.Marshal(r)
}

type Root struct {
	ID      int64    `json:"id"`
	Name    string   `json:"name"`
	Score   float64  `json:"score"`
	Tags    []string `json:"tags"`
	Address Address  `json:"address"`
	Orders  []Order  `json:"orders"`
}

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

type Order struct {
	ID    string  `json:"id"`
	Total float64 `json:"total"`
	Paid  bool    `json:"paid"`
}
Open this example in the tool

Webhook events with optional fields

Fields missing from one event become pointers, reason is an interface{} because it is only ever null, and the root is a slice type.

Input
[
  { "type": "invoice.paid", "created": 1789475200, "amount": 12990, "customer": "cus_42" },
  { "type": "invoice.voided", "created": 1789478800, "reason": null }
]
Output
// To parse and unparse this JSON data, add this code to your project and do:
//
//    events, err := UnmarshalEvents(bytes)
//    bytes, err = events.Marshal()

package main

import "encoding/json"

type Events []Event

func UnmarshalEvents(data []byte) (Events, error) {
	var r Events
	err := json.Unmarshal(data, &r)
	return r, err
}

func (r *Events) Marshal() ([]byte, error) {
	return json.Marshal(r)
}

type Event struct {
	Type     string      `json:"type"`
	Created  int64       `json:"created"`
	Amount   *int64      `json:"amount,omitempty"`
	Customer *string     `json:"customer,omitempty"`
	Reason   interface{} `json:"reason"`
}
Open this example in the tool

Common errors and how to fix them

ErrorCauseFix
The JSON key "a,b" cannot be named in a Go json tag (empty or containing a comma); that field will not be decodedA warning: encoding/json uses commas to separate tag options, so the key cannot be matched.Decode that object into a map[string]any, or implement UnmarshalJSON for the struct.
Some integers are larger than 2^53; they are typed as floating-point numbers. Use a 64-bit or big-integer type if you need exact values.
Explained
A warning: the sample holds integers too large for exact inference.Change the field to int64 (if it fits), uint64, json.Number or string.
Trailing comma before '}'
Explained
The sample is not valid JSON.Remove the trailing comma, or repair the sample in the JSON formatter first.

Frequently asked questions

Why are some fields pointers?

A pointer distinguishes “missing or null” from the zero value. Fields that are absent from some samples or null in some get a pointer type; required fields stay plain values.

Why int64 rather than int?

int64 has the same size on every platform, so the struct decodes identically everywhere. Change it to int if you prefer.

Can I use the structs with other JSON libraries?

Yes. Libraries such as jsoniter, sonic and goccy/go-json read the same json struct tags.

Does the generated code need external packages?

No. It only imports encoding/json, plus bytes and errors when a union type needs helper functions.

Related tools