Skip to content
Runtime
Framework

Zod, Valibot, ArkType

All three libraries implement Standard Schema v1, so all three work identically through fromStandardSchema. QueryWeave has no preference and no default: pick on the merits of the library, not on what this documentation happens to show first.

A search term of at least two characters:

import { fromStandardSchema } from "@queryweave/standard-schema";
import { defineQueryModel, param } from "@queryweave/core";
import { z } from "zod";
const search = param
.text()
.refine(fromStandardSchema(z.string().min(2)))
.optional();
const products = defineQueryModel({ search });

Whichever you choose, a rejected value produces the same thing:

const result = products.decode("?search=v");
result.issues[0]?.code; // "validation_failed"
result.issues[0]?.key; // "search"
result.ok && result.value.search; // undefined — optional presence recovered
const products = defineQueryModel({
search: param.text().refine(fromStandardSchema(z.string().transform((value) => value.length))),
});
const result = products.decode("?search=vue");
if (result.ok) result.value.search; // 3, inferred as number

In all three cases the parameter’s value type becomes number, inferred from the schema’s output.

const priceFilters = defineQueryModel(
{ minPrice: param.number({ min: 0 }), maxPrice: param.number({ min: 0 }) },
{
refine: [
fromStandardSchema(
z
.object({ minPrice: z.number(), maxPrice: z.number() })
.refine((filters) => filters.minPrice <= filters.maxPrice),
),
],
},
);

The URL and QueryWeave result are identical for all three versions:

const result = priceFilters.decode("?minPrice=200&maxPrice=100");
result.ok; // false
result.issues[0]?.code; // "validation_failed"
result.issues[0]?.key; // "$" — exported as modelIssueKey

The repository’s compatibility suite runs a single table of expectations across all three vendors:

Behavior Verified
A valid value passes through unchanged yes
A rejected value produces validation_failed yes
Recovery follows the parameter’s presence yes
A transform changes the inferred type yes
A model-level schema reports under $ yes
The vendor’s error type never escapes yes

That is the contract. If a fourth Standard Schema library satisfies it, it works — nothing about these three is special-cased.

QueryWeave takes no position. The practical differences are the usual ones: Zod is the most widely known, Valibot is designed around tree-shaking, ArkType parses type-level syntax. All three produce identical QueryWeave issues, so this decision is reversible.