Skip to content
TypeParser
All tools

JSON to Go Struct

Generate Go structs from JSON.

beats mholt.github.io/json-to-go edge: Inline nested struct generation
JSON
paste JSON
Guide

About JSON to Go Struct

Build Go struct definitions with proper JSON tags from any JSON sample. Handles nested objects via inline structs, arrays as slices, and ISO date strings as <code>time.Time</code>. Output is ready to paste into a Go source file — compiles without modification.

Why generate Go structs

Hand-typing a 30-field struct with correct tags is busywork. Tools like mholt/json-to-go solved this years ago for Go developers; this is the same idea, in your browser, with a few modern niceties (time.Time inference, omitempty toggling, named-vs-inline).

What you get

type User struct {
    ID        int    `json:"id"`
    Email     string `json:"email"`
    Name      string `json:"name"`
    Tags      []string `json:"tags,omitempty"`
    Address   struct {
        Street string `json:"street"`
        City   string `json:"city"`
        State  string `json:"state"`
        Zip    string `json:"zip"`
    } `json:"address"`
    CreatedAt time.Time `json:"created_at"`
}

Common workflows

Type an API client. Generate structs from the API’s sample response, drop into a types.go, use with json.Unmarshal or your client library.

Stub a service handler. Generate request and response structs from a contract example, write the handler against them.

Move from interface{} to typed. A Go service using map[string]interface{} can be partially typed by generating structs from a sample and refactoring incrementally.

Edge cases worth knowing

  • Sums / discriminated unions — Go has no native enum, no native sum type. The tool produces a string field; you add a custom UnmarshalJSON if you need typed variants.
  • Numbers without decimal — typed as int. If you receive 1.0 as a number, that becomes int; if your data later includes 1.5, the generated type won’t fit. Inspect a richer sample.
  • Empty arrays — typed as []interface{} (we cannot infer element type from an empty array). Add a non-empty sample.

For runtime validation alongside the types, pair with a validation library (go-playground/validator).

Frequently asked questions

Inline vs named nested types?
Inline (the default) keeps everything in one declaration — compact, easy to scan. Named extracts each nested object to its own type — better for refactoring and reuse.
How are JSON tags formatted?
json:"field_name". Field names that differ from Go's PascalCase get an explicit tag. We also emit json:"field,omitempty" for fields that are optional in the input.
Snake_case to PascalCase?
Yes. created_at becomes CreatedAt with json:"created_at". Standard Go convention.
How are dates handled?
ISO 8601 strings become time.Time. The json package parses RFC 3339 by default — everything works without custom unmarshaling.
What about pointers?
Toggle Pointer optional to use *string for fields that can be null. Without the toggle, optional fields use omitempty + zero values.
Generate package boilerplate?
Toggle Include package + imports to add the package main line and required imports.

Related tools

Last updated: 2025-01-15