<- Back to BlogCode Generation

JSON to Go, Pydantic, and Zod: Code Generators Compared (2026)

Need types from a sample payload?

Use JSON to Go for structs, JSON to Pydantic for Python models, or JSON to Zod for TypeScript runtime validation. Review generated code before treating it as a contract.

A JSON sample is evidence about one payload, not a complete API contract. Code generators turn that evidence into a useful starting point for a language-specific type system. The best generator matches the code that will consume the data and makes uncertainty visible instead of pretending every field is known.

1. Choose by runtime and purpose

GeneratorBest fitWhat it gives you
JSON to GoGo servicesStructs, tags, pointers, and nested types
JSON to PydanticPython APIsBaseModel classes, aliases, and parsing
JSON to ZodTypeScript appsRuntime schemas and inferred types

None can infer fields that never appeared, distinguish a stable integer from an occasional string, or decide whether missing should be optional or invalid. Those decisions belong to the contract owner.

2. What one sample can and cannot tell you

Collect success, empty, partial, and error responses. A generator can infer a current type, but not whether a field is always present, whether an ID is a UUID, or whether a server sometimes returns null. Generate from representative fixtures with credentials removed.

{
  "id": 42,
  "name": "Ada",
  "tags": ["admin", "billing"],
  "profile": { "timezone": "UTC" }
}

3. JSON to Go structs

Go structs are explicit data-transfer objects. JSON tags preserve wire names when Go naming differs. Pointer fields help when missing must be distinguished from a zero value; value fields are simpler when the API guarantees presence. Adding pointers everywhere makes callers handle nil values without improving correctness.

type Profile struct {
    Timezone string
}

type User struct {
    ID      int
    Name    string
    Tags    []string
    Profile Profile
}

Polymorphic JSON may require custom unmarshalling or a discriminated union design. Generated structs are a starting point, not a reason to ignore API compatibility.

4. Pydantic models

Pydantic combines Python annotations with runtime parsing, which is useful at API boundaries. Pydantic v1 and v2 differ in configuration and serialization, so choose the target version explicitly. Aliases matter when JSON uses camelCase but Python uses snake_case. Decide whether unknown fields are ignored, allowed, or rejected.

from pydantic import BaseModel

class User(BaseModel):
    id: int
    name: str
    tags: list[str]

5. Zod schemas

Zod is executable at runtime. Parse unknown network data with the schema, then infer the TypeScript type from that same schema. An interface alone disappears after compilation and cannot validate a response.

import { z } from "zod";

const UserSchema = z.object({
  id: z.number().int(),
  name: z.string(),
  tags: z.array(z.string())
});

type User = z.infer<typeof UserSchema>;

Refine generated schemas with URL checks, enums, minimum lengths, nullable fields, and an intentional unknown-key policy. Use discriminated unions when a reliable kind field exists.

6. Production workflow

  1. Collect several real payloads and redact credentials or personal data.
  2. Generate a first model for the language your service uses.
  3. Review naming, optionality, nullability, numeric ranges, and unknown fields.
  4. Commit models beside contract tests, not as unreviewed generated output.
  5. Validate success and failure payloads in CI.
  6. Regenerate only when the input contract intentionally changes.

The JSON to Go Generator, JSON to Pydantic Generator, and JSON to Zod Generator run locally in the browser. Use representative fixtures rather than live secrets.

7. Common mistakes

  • Making every field optional: the type becomes easy to compile but hard to use safely.
  • Confusing null with missing: clients may need different behavior for each.
  • Trusting inferred numbers: IDs can exceed safe JavaScript precision or arrive as strings.
  • Ignoring unknown fields: additive API changes can go unnoticed.
  • Using interfaces as validation: interfaces do not inspect runtime data.
  • Generating from one happy path: arrays, errors, and empty states reveal the real contract.

Validate fixtures with the JSON Validator and keep a human-owned contract around generated code.

Conclusion

Code generation saves typing, not design decisions. Choose Go for explicit structs, Pydantic for Python boundary validation, and Zod when TypeScript needs runtime parsing. Generate locally, review uncertainty, and test variations.

Frequently Asked Questions

Which generator should I use?
Use JSON to Go for Go services, JSON to Pydantic for Python models, and JSON to Zod when TypeScript needs runtime validation.
Can a generator create a complete API contract?
No. A sample cannot reveal absent fields, future variants, or business constraints.
Should generated fields be optional?
Only when the API can omit them or missing data is valid.
What is the difference between an interface and Zod?
A TypeScript interface is removed at runtime; a Zod schema can parse and reject data.
When should Go use pointers?
Use pointers when missing and zero values must be distinguished.
Why do Pydantic aliases matter?
They let Python naming differ from the JSON wire name while preserving serialization behavior.