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/valibotnpm add @optique/valibot valibotpnpm add @optique/valibot valibotyarn add @optique/valibot valibotbun add @optique/valibot valibotNOTE
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.