Skip to content

Generate TypeScript Zod Schemas from Rust

The ZodTs derive macro generates TypeScript Zod schema code from Rust types, enabling shared validation between your Rust backend and TypeScript frontend.

Add the dependency:

[dependencies]
zod-rs = { version = "1.0", features = ["ts"] }
# Or use the standalone crate
zod-rs-ts = "1.0"
use zod_rs_ts::ZodTs;
#[derive(ZodTs)]
struct User {
#[zod(min_length(2), max_length(50))]
username: String,
#[zod(email)]
email: String,
#[zod(min(18.0), max(120.0), int)]
age: u32,
bio: Option<String>,
}
fn main() {
let ts_code = User::zod_ts();
println!("{}", ts_code);
// Write to file
std::fs::write("schemas/user.ts", ts_code).unwrap();
}

The above generates:

import * as z from "zod";
export const UserSchema = z.object({
username: z.string().min(2).max(50),
email: z.string().email(),
age: z.number().int().min(18).max(120),
bio: z.string().optional()
});
export type User = z.infer<typeof UserSchema>;

The generator targets Zod v4 by default, which uses a namespace import (import * as z from "zod"). To emit legacy Zod v3 imports (import { z } from 'zod'), enable the zod-v3 feature:

[dependencies]
zod-rs = { version = "...", features = ["ts", "zod-v3"] }
# or, directly:
zod-rs-ts = { version = "...", features = ["zod-v3"] }

The field/validator output is identical across both versions — only the import statement changes.

Generated schemas are Standard Schema compliant out of the box. This is provided by Zod itself: every Zod v3.24+ and Zod v4 schema implements the ~standard interface natively.

That means the generated output works directly with any Standard Schema consumer — TanStack Form, React Hook Form, and other validation-library-agnostic tooling — with no adapter code.

Rust TypeTypeScript Zod
Stringz.string()
f32, f64z.number()
i8..i64, u8..u64z.number().int()
boolz.boolean()
Vec<T>z.array(T)
Option<T>T.optional()

The same #[zod(...)] attributes used with ZodSchema are translated to TypeScript Zod methods. See the attributes reference for the full list.