Type-safe URL search parameters using Zod schemas.
npm install @falkz/zod-search-params zod
import { z } from "zod/v4";
import { searchParamsObject, toSearchParams } from "@falkz/zod-search-params";
const schema = searchParamsObject({
query: z.string(),
page: z.number(),
limit: z.number().optional(),
active: z.boolean(),
});
// Parse
const params = schema.parse("?query=hello&page=1&active=true");
// { query: 'hello', page: 1, limit: undefined, active: true }
// Serialize
const urlParams = toSearchParams({ query: "world", page: 2, active: false });
// URLSearchParams { 'query' => 'world', 'page' => '2' }
searchParamsObject()
behaves the same way as z.object()
. This means as long as you use supported values you can create the schema in the same way as you are used to from zod.
import { z } from "zod/v4";
import { searchParamsObject } from "@falkz/zod-search-params";
const schema = searchParamsObject({
name: z.string(),
age: z.number(),
active: z.boolean().optional(),
});
type InferredType = z.infer<typeof schema>;
const typedObject = schema.parse("name=john&age=25&active=true");
// or
const typedObject = schema.parse(new URLSearchParams("name=john&age=25"));
// or
const typedObject = schema.parse(window.location.search);
These are all the values the searchParamsObject
accepts:
z.string()
,z.number()
,z.bigint()
,z.boolean()
z.literal()
z.email()
,z.url()
,z.uuid()
, etc.z.enum()
z.templateLiteral()
.optional()
modifier
If the value is not supported, typescript will let you know that you passed in a value that does not work.
toSearchParams
converts an object to URLSearchParams. When parsed again by searchParamsObject
the same object will be recreated.
import { toSearchParams } from "@falkz/zod-search-params";
// create new params:
const params = toSearchParams({
query: "hello",
page: 1,
active: true,
disabled: false,
empty: undefined,
});
// or update existing params:
const updatedParams = toSearchParams(
{
query: "hello",
page: 1,
active: true,
disabled: false,
empty: undefined,
},
window.location.search,
);