Guide
Generate Zod, Go, Rust, and Pydantic from JSON
Types are not only a TypeScript concern. The same JSON sample can generate a Zod validator, a Go or Rust struct, or a Pydantic model, so whatever language you work in, you can turn a payload into typed code in one step. This guide covers the main targets and what makes each useful.
One sample, many targets
The generator infers a shape from your JSON sample and then emits that shape in the language you pick. Start from this payload:
{
"id": 42,
"name": "Ada",
"roles": ["admin", "editor"],
"active": true
}Zod: validation for TypeScript
TypeScript interfaces disappear at runtime, so they cannot check data that arrives from outside your program. Zod schemas do the checking at runtime and give you a TypeScript type for free.
import { z } from "zod";
export const Root = z.object({
id: z.number(),
name: z.string(),
roles: z.array(z.string()),
active: z.boolean(),
});
export type Root = z.infer<typeof Root>;Parse untrusted JSON through the schema at the boundary. If it does not match, Zod throws with a clear reason, so bad data fails fast instead of spreading through your app as a wrong type.
Go and Rust structs
Compiled languages want a struct to unmarshal JSON into. Generating it saves you writing the fields and the tags by hand.
type Root struct {
ID int `json:"id"`
Name string `json:"name"`
Roles []string `json:"roles"`
Active bool `json:"active"`
}use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)]
struct Root {
id: i64,
name: String,
roles: Vec<String>,
active: bool,
}The Go output includes the json struct tags that map field names, and the Rust output derives serde's Serialize and Deserialize so the struct works with the standard JSON crate.
Pydantic for Python
Pydantic models validate and parse data in Python, which makes them a natural target for JSON coming into a service or script.
from pydantic import BaseModel
class Root(BaseModel):
id: int
name: str
roles: list[str]
active: boolConstruct the model from parsed JSON and Pydantic checks the types and required fields, raising a validation error when something is off.
The same caveat applies everywhere
Whatever target you choose, the output is only as good as the sample. A field that is null or missing in your JSON cannot be inferred as optional or nullable on its own. Feed the generator a payload that shows the real range of values, then tighten optional and nullable fields in the generated code to match what the source actually returns.
Because every target comes from the same inferred shape, the Zod schema, the Go struct, and the Pydantic model all agree with each other. That consistency is the point: one sample, one contract, expressed in whatever language needs it.
FAQ
Why generate Zod instead of a TypeScript interface?
A TypeScript interface is erased at runtime and cannot validate incoming data. A Zod schema checks data at runtime and also gives you a matching TypeScript type through z.infer.
Do the Go and Rust outputs include serialization support?
Yes. The Go struct includes json tags for field mapping, and the Rust struct derives serde's Serialize and Deserialize so it works with the standard JSON tooling.
How do I handle fields that are sometimes null?
A single sample cannot express that. Provide a sample showing the null case, or mark the field optional or nullable in the generated code to match what the API returns.