DEV Community

Jop
Jop

Posted on

How accurate are JSON Zod generators actually? I compared three on the same input

I've been relying on JSON→Zod generators to scaffold schemas from API responses,
and kept wondering — how much do they actually infer vs just dumping z.string()?
So I ran three tools on the same payload to find out.

Input (same for all):

{ "status": "active", "email": "a@b.com", "id": "a1b2c3d4-…",
  "joined": "2026-01-01T00:00:00Z", "age": 30, "website": "https://a.com" }
Enter fullscreen mode Exit fullscreen mode

json-to-zod

z.object({
  status: z.string(), email: z.string(), id: z.string(),
  joined: z.string(), age: z.number(), website: z.string(),
})
Enter fullscreen mode Exit fullscreen mode

Zero format detection. Technically correct, validates nothing.

quicktype (-l typescript-zod)

z.object({
  status: z.string(), email: z.string(), id: z.string(),
  joined: z.coerce.date(), // caught the date
  age: z.number(), website: z.string(),
})
Enter fullscreen mode Exit fullscreen mode

1 out of 6. Better, but stops there.

TypeMorph (disclosure: side project I built — take with salt)

z.object({
  status: z.enum(["active", "pending", "closed"]),
  email: z.email(),
  id: z.uuid(),
  joined: z.iso.datetime(),
  age: z.number().int().min(0).max(150),
  website: z.url(),
})
Enter fullscreen mode Exit fullscreen mode

The interesting design questions this raised for me:

  • Enums from a single sample → you get z.enum(["active"]) which rejects valid future values. You need multiple samples aggregated before enums are safe. Worth it?
  • Name-based heuristics (age → .int().min(0).max(150)) — useful shortcut or too opinionated?
  • Open-vocab fields like currency or country should stay z.string() even if they look like enums

Is anyone doing something smarter here? Curious what approach others take
when generating schemas from real API data.

Top comments (0)