Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

JSON to Go Struct

Paste JSON, get Go structs with json tags that unmarshal it.

Developer No upload Works offline Free, no sign-up

One JSON document, or several samples one after another or one per line (JSON Lines). Comments and trailing commas are ignored. Your data stays in this browser.

Besides json, e.g. yaml, xml, bson, db, mapstructure.
Type inference

Next steps

About the JSON to Go Struct

Paste a JSON response and get Go structs that encoding/json can unmarshal it into. Every field is exported (full_name → FullName) and keeps its JSON name in a json:"…" tag; nested objects become named struct types, arrays become slices, integers int64, decimals float64 and RFC 3339 timestamps time.Time. A field that is missing from some samples becomes a pointer with omitempty, and one that is sometimes null becomes a pointer, so you can tell "absent" from a zero value.

Add yaml, db, bson or other tags next to json, choose the package name, add UnmarshalX/Marshal helpers, or split the result into one file per type and download them as a ZIP. Everything runs in your browser — the JSON never leaves your device.

How to use it

  1. Paste JSON or open or drop a .json file, or press Load sample. Several samples one after another (or JSON Lines) give more accurate optional fields.
  2. Set the Root type name (for example Repository) and the Package.
  3. Add extra struct tags, for example yaml, db; each gets the JSON name. Untick omitempty if empty values must still be written.
  4. Tick Unmarshal/Marshal helpers for ready-made functions, or One file per type for a file per struct.
  5. Copy the code, download the .go file, or download all files as a ZIP.

Examples

Nullable and optional fields become pointers
Input
{"id": 1, "license": null, "homepage": "https://example.com", "created_at": "2011-01-26T19:01:12Z"}
{"id": 2, "license": {"key": "mit"}, "created_at": "2011-01-27T19:30:43Z"}
Result
type Root struct {
	ID        int64     `json:"id"`
	License   *License  `json:"license"`
	Homepage  *string   `json:"homepage,omitempty"`
	CreatedAt time.Time `json:"created_at"`
}

type License struct {
	Key string `json:"key"`
}

license is null in one sample (pointer, always written); homepage is missing from one (pointer with omitempty).

Extra tags for YAML and SQL
Input
{"user_id": 7, "nick": "a"}
{"user_id": 8}
Result
type Row struct {
	UserID int64   `json:"user_id" yaml:"user_id" db:"user_id"`
	Nick   *string `json:"nick,omitempty" yaml:"nick,omitempty" db:"nick,omitempty"`
}

Extra tags: yaml, db, root type name Row.

Repeated values become typed constants
Input
[{"role": "admin"}, {"role": "editor"}, … 12 users with three roles]
Result
type Users []User

type User struct {
	Role Role `json:"role"`
}

type Role string

const (
	Admin  Role = "admin"
	Editor Role = "editor"
	Viewer Role = "viewer"
)

Common uses

  • Writing the client for a REST API in Go without typing every struct by hand.
  • Reading JSON or YAML config files into typed structs (add the yaml tag).
  • Mapping API payloads to database rows with db tags for sqlx or similar libraries.
  • Turning a JSON Schema from an OpenAPI spec into Go types.

Pointers, omitempty and zero values

encoding/json leaves a field at its zero value ("", 0, false) when the key is missing, so a plain string cannot tell "missing" from "empty". That is why optional and nullable fields are pointers: nil means absent or null.

omitempty only matters when you marshal: the field is left out when its value is empty — false, 0, a nil pointer, a nil interface, or an array, slice, map or string of length zero. A struct value such as time.Time is never "empty", so omitempty does not drop it; Go 1.24 added the omitzero option for that, which you can write by hand. Fields that are present in every sample but sometimes null are pointers without omitempty, so null is written back as null.

How names and types are chosen

  • Field names are exported Go names: full_name → FullName, id → ID, spdx_id → SpdxID. The json tag keeps the exact JSON name, so unmarshalling does not depend on Go's case-insensitive matching.
  • Integers → int64; numbers with decimals (in any sample) → float64; booleans → bool; RFC 3339 date-times → time.Time (untick Dates as time.Time to keep string); anything that is always null or mixed → interface{}.
  • Nested objects get their own named struct types, named after the property (arrays in the singular: items → Item). Objects with many keys that look like data become map[string]T.
  • A string property with at least 10 values in your samples and only a few distinct ones becomes a named string type with constants, such as type Role string.

Helpers and multiple files

With Unmarshal/Marshal helpers the code starts with func UnmarshalRepository(data []byte) (Repository, error) and a Marshal method, plus the // Code generated … DO NOT EDIT. comment that Go tools recognise. One file per type writes repository.go, owner.go, … each with its own package clause and imports; Download all (.zip) saves them together.

Limitations

  • Types are inferred from your samples only: a field seen once as a number is int64 even if the API can send a string. Paste several real responses.
  • Nested structs are always named types; the tool does not write anonymous inline structs.
  • JSON Schema references must point inside the schema (#/$defs/…); validation keywords such as minimum or pattern have no Go equivalent and are left out.
  • Integers larger than 64 bits do not fit in int64 — the notes point them out; keep such values as strings.

Privacy

Everything happens in your browser. What you enter or open here is not uploaded or stored by MySmartCoPilot. The code generator (about 330 KB compressed) is downloaded from this site once, like the rest of the page; your JSON is never uploaded.

Frequently asked questions

Is my JSON sent to a server?

No. The structs are generated in your browser, in a background worker, and the page works offline once loaded.

Why are some fields pointers?

Because they were missing or null in at least one sample. A pointer lets your code see the difference between "not sent" (nil) and a real zero value. If a field is always present in practice, add a sample that shows it and it becomes a plain value.

Do I need the json tags if the names already match?

encoding/json would still match a key such as full_name only if the field had the same name ignoring case — FullName does not match full_name without a tag. The tags make the mapping exact in both directions.

Why does a field with omitempty still appear as "created_at": "0001-01-01T00:00:00Z"?

Because omitempty never treats a struct value such as time.Time as empty. Make the field a pointer (*time.Time) or use the omitzero tag option from Go 1.24.

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.