Andre Treib's Two Cents

Zod Finally Solves Your Transform Headaches

ANAndré Treib

Published on August 26, 2025

Hey friends! Sit down with your fave café-style beverage—let’s unpack the freshly dropped z.codec() feature in Zod 4.1, brought to us by the legend himself, @colinhacks.

The “Oops, Transform Was Only One‑Way” Problem

Zod’s .transform() method is awesome for one-way data conversion. Want to turn strings into numbers? Easy:

const stringToNumber = z.string().transform(val => parseFloat(val));

stringToNumber.parse("42"); // 42

But here’s the catch: things get brittle when you need two-way transformations—say, converting ISO date strings to Date objects and back again. You either maintain two separate schemas (and pray they stay in sync) or end up tangled in subtle bugs.

Enter z.codec(): Bidirectional Bliss

z.codec() is the shiny new Zod API that lets you define bi-directional transformations with a single schema:

const stringToDate = z.codec(z.iso.datetime(),z.date(), { decode: iso => new Date(iso), encode: date => date.toISOString() } );

Now you can go both ways with confidence:

stringToDate.decode("2024‑01‑15T10:30:00.000Z"); // → Date

stringToDate.encode(new Date("2024‑01‑15")); // → "2024‑01‑15T00:00:00.000Z"

.parse() vs .decode(): Same Runtime, Different Type Safety

  • .parse(): accepts unknown, runtime-checked.
  • .decode(): expects strictly typed input—hello, TypeScript compile-time safety!
stringToDate.parse(12345); // no TS error, but fails at runtime

stringToDate.decode(12345); // TS error: number isn’t assignable to string

TL;DR – Why You’ll ♥ z.codec()

  • Solves two-way transform pain: Keep data and code in sync with one elegant schema.
  • TypeSafe Superpowers: .decode() gives you compile-time safety.
  • Flexible & safe: Supports async, safe variants, refinements, and more.
  • Composable: Nest within bigger schemas to keep transformations local and clean.
  • Copy-paste convenience: Official examples mean less guesswork.

If you're doing things like serializing dates, parsing bigint, or juggling JSON representations, z.codec() feels like sliding into your dev setup wearing your favorite rock tee—it just fits. What transformation are you thinking of turning around next?

Published on August 26, 2025

André TreibAN