Skip to content

Zod integration

This API is available since Optique 0.7.0.

The @optique/zod package provides seamless integration with Zod, enabling you to use Zod schemas for validating command-line arguments. This allows you to leverage Zod's powerful validation capabilities and reuse existing schemas across your CLI and application code.

deno add jsr:@optique/zod zod
npm add @optique/zod zod
pnpm add @optique/zod zod
yarn add @optique/zod zod
bun add @optique/zod zod

Basic usage

The zod() function creates a value parser from any Zod schema:

import { 
zod
} from "@optique/zod";
import {
z
} from "zod";
// Email validation const
email
=
zod
(
z
.
string
().
email
(), {
placeholder
: "" });
// Port number with range validation const
port
=
zod
(
z
.
coerce
.
number
().
int
().
min
(1024).
max
(65535), {
placeholder
: 1024 });
// Enum choices const
logLevel
=
zod
(
z
.
enum
(["debug", "info", "warn", "error"]), {
placeholder
: "debug" });

IMPORTANT

The options object is required. In particular, placeholder must be a valid stand-in value of the schema's output type. Optique uses it during deferred prompt resolution, so it does not need to be meaningful user data, but it must be safe for downstream transforms.

String coercion

CLI arguments are always strings, so use z.coerce for non-string types:

// ✅ Correct: Use z.coerce for numbers
const 
age
=
zod
(
z
.
coerce
.
number
().
int
().
min
(0), {
placeholder
: 0 });
// ❌ Won't work: z.number() expects actual numbers, not strings const
num
=
zod
(
z
.
number
(), {
placeholder
: 0 });

NOTE

Both z.boolean() and z.coerce.boolean() are handled specially: instead of rejecting CLI strings or applying JavaScript truthiness semantics, Optique accepts CLI-friendly literals (true/false, 1/0, yes/no, on/off, case-insensitive).

Transformations

Zod's transformation capabilities work seamlessly with Optique:

// Parse and transform to Date
const 
startDate
=
zod
(
z
.
string
().
transform
((
s
) => new
Date
(
s
)), {
placeholder
: new
Date
(0) });
// Transform to uppercase const
name
=
zod
(
z
.
string
().
transform
((
s
) =>
s
.
toUpperCase
()), {
placeholder
: "" });

Custom error messages

Customize error messages for better user experience:

const 
email
=
zod
(
z
.
string
().
email
(), {
placeholder
: "",
metavar
: "EMAIL",
errors
: {
zodError
: (
error
,
input
) =>
message
`Please provide a valid email address, got ${
input
}.`
} });

Integration with Optique

Zod parsers work seamlessly with all Optique features:

import { 
object
} from "@optique/core/constructs";
import {
option
,
argument
} from "@optique/core/primitives";
import {
zod
} from "@optique/zod";
import {
z
} from "zod";
const
config
=
object
({
email
:
option
("--email",
zod
(
z
.
string
().
email
(), {
placeholder
: "" })),
port
:
option
("-p", "--port",
zod
(
z
.
coerce
.
number
().
int
().
min
(1024).
max
(65535), {
placeholder
: 1024 })),
logLevel
:
option
("--log-level",
zod
(
z
.
enum
(["debug", "info", "warn", "error"]), {
placeholder
: "debug" })),
startDate
:
argument
(
zod
(
z
.
string
().
transform
((
s
) => new
Date
(
s
)), {
placeholder
: new
Date
(0) })),
});

Version compatibility

The @optique/zod package supports both Zod v3 (3.25.0+) and Zod v4 (4.0.0+):

  • Zod v3: Uses standard error messages from error.issues[0].message
  • Zod v4: Automatically uses prettifyError() when available for better error formatting

Limitations

  • Async refinements not supported: Since Optique's parsing is synchronous, async Zod features like refine(async ...) cannot be used. Async boolean schemas are detected when a valid boolean literal is parsed ("true", "false", etc.) and throw a TypeError; unrecognized inputs like "maybe" return a normal validation error instead. Perform async validation after parsing if needed.

  • Boolean parsing in unions: The CLI-friendly boolean parsing (accepting true/false, 1/0, yes/no, on/off) applies only when the entire schema is recognized as a boolean type. For unions that are not recognized as wholly boolean, arm precedence is preserved and parsing follows Zod's native union/coercion behavior.

The Zod integration provides a powerful way to reuse validation logic across your entire application while maintaining full type safety and excellent error messages.