Skip to content

Valibot integration

This API is available since Optique 0.7.0.

The @optique/valibot package provides seamless integration with Valibot, enabling you to use Valibot schemas for validating command-line arguments. Valibot is a modular validation library with a significantly smaller bundle size (~10KB) compared to Zod (~52KB), making it ideal for CLI applications where bundle size matters.

deno add --jsr @optique/valibot @valibot/valibot
npm add @optique/valibot valibot
pnpm add @optique/valibot valibot
yarn add @optique/valibot valibot
bun add @optique/valibot valibot

NOTE

When using Deno, import Valibot from @valibot/valibot instead of valibot:

import * as v from "@valibot/valibot";
import * as v from "valibot";
import * as v from "valibot";

Basic usage

The valibot() function creates a value parser from any Valibot schema:

import { 
valibot
} from "@optique/valibot";
import * as
v
from "valibot";
// Email validation const
email
=
valibot
(
v
.
pipe
(
v
.
string
(),
v
.
email
()), {
placeholder
: "" });
// Port number with range validation const
port
=
valibot
(
v
.
pipe
(
v
.
string
(),
v
.
transform
(
Number
),
v
.
number
(),
v
.
integer
(),
v
.
minValue
(1024),
v
.
maxValue
(65535)
), {
placeholder
: 0 },
); // Picklist choices const
logLevel
=
valibot
(
v
.
picklist
(["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.

Explicit transformations

CLI arguments are always strings, so use explicit v.transform() for non-string types:

// ✅ Correct: Use v.pipe with v.transform for numbers
const 
age
=
valibot
(
v
.
pipe
(
v
.
string
(),
v
.
transform
(
Number
),
v
.
number
(),
v
.
minValue
(0)),
{
placeholder
: 0 },
); // ❌ Won't work: v.number() expects actual numbers, not strings const
num
=
valibot
(
v
.
number
(), {
placeholder
: 0 });

Transformations

Valibot's transformation capabilities work seamlessly with Optique:

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

Custom error messages

Customize error messages for better user experience:

const 
email
=
valibot
(
v
.
pipe
(
v
.
string
(),
v
.
email
()), {
placeholder
: "",
metavar
: "EMAIL",
errors
: {
valibotError
: (
issues
,
input
) =>
message
`Please provide a valid email address, got ${
input
}.`
} });

Integration with Optique

Valibot parsers work seamlessly with all Optique features:

import { 
object
} from "@optique/core/constructs";
import {
option
,
argument
} from "@optique/core/primitives";
import {
valibot
} from "@optique/valibot";
import * as
v
from "valibot";
const
config
=
object
({
email
:
option
("--email",
valibot
(
v
.
pipe
(
v
.
string
(),
v
.
email
()), {
placeholder
: "" })),
port
:
option
(
"-p", "--port",
valibot
(
v
.
pipe
(
v
.
string
(),
v
.
transform
(
Number
),
v
.
number
(),
v
.
integer
(),
v
.
minValue
(1024),
v
.
maxValue
(65535)
), {
placeholder
: 0 },
) ),
logLevel
:
option
(
"--log-level",
valibot
(
v
.
picklist
(["debug", "info", "warn", "error"]), {
placeholder
: "debug" }),
),
startDate
:
argument
(
valibot
(
v
.
pipe
(
v
.
string
(),
v
.
transform
((
s
) => new
Date
(
s
))), {
placeholder
: new
Date
(0) }),
), });

Version compatibility

The @optique/valibot package currently targets Valibot 1.x.

Limitations

  • Async validations not supported: Since Optique's parsing is synchronous, async Valibot features like pipeAsync() cannot be used. Perform async validation after parsing if needed.

The Valibot integration provides a lightweight yet powerful way to reuse validation logic across your entire application while maintaining full type safety, excellent error messages, and minimal bundle size.