theboxer/zod-search-params(opens in a new tab)
Language: TypeScript
Zod utility for parsing search params
- stars
- 15
- watchers
- 1
- forks
- 0
- open issues
- 0
- Last updated
- 01/13/2026
Language: TypeScript
Zod utility for parsing search params
zod-search-params is a library for parsing and validating search params in the browser.
yarn add zod-search-params
import { parseSearchParams } from 'zod-search-params'; // by default this imports version for zod v3 // or import { parseSearchParams } from 'zod-search-params/v3'; // specifically import version for zod v3 // or import { parseSearchParams } from 'zod-search-params/v4'; // specifically import version for zod v4
Do NOT use coerce in the schema, coerce is applied automatically (to prevent casting undefined to "undefined" etc.) for enabled types, when it's needed.
const schema = z.object({ search: z.string().catch(''), page: z.number().catch(1), });
import { parseSearchParams } from 'zod-search-params'; const parsedSearchParams = parseSearchParams(schema, urlSearchParams);
If all object properties within the zod schema are defined with .catch(), the output will always be an object with the same properties as the schema, but with the default values.
import { parseSearchParams } from 'zod-search-params'; const schema = z.object({ search: z.string().catch(''), page: z.number().catch(1), }); const parsedSearchParams = parseSearchParams(schema); /* typeof parsedSearchParams { search: string, page: number, } */
If one or all object properties within the zod schema don't have .catch(), the output will be an object with the same properties as the schema or undefined. Where the undefined will return if parsing of the search params fail (for example passing string into a number).
import { parseSearchParams } from 'zod-search-params'; const schema = z.object({ search: z.string().catch(''), page: z.number(), }); const parsedSearchParams = parseSearchParams(schema); /* typeof parsedSearchParams undefined | { search: string, page: number, } */
Using .optional() on a property will make the property optional, can be also chained with .default() to provide a default value.
import { parseSearchParams } from 'zod-search-params'; const schema = z.object({ search: z.string().catch(''), page: z.number().optional().catch(undefined), sort: z.string().optional().default('name').catch('name'), }); const parsedSearchParams = parseSearchParams(schema); /* typeof parsedSearchParams { search: string, page?: number, sort: string, } */
import { URLSearchParams } from 'url'; const schema = z.object({ search: z.string().catch(''), page: z.number().catch(1), }); const objectParams = { search: 'hello', page: '2', }; const urlParams = new URLSearchParams(); urlParams.append('search', 'hello'); urlParams.append('page', '2'); console.log(parseSearchParams(schema, objectParams)); console.log(parseSearchParams(schema, urlParams)); /* OUTPUTS: { search: 'hello', page: 2, } */
import { URLSearchParams } from 'url'; const schema = z.object({ tags: z.array(z.string()).catch([]), ids: z.array(z.number()).catch([]), }); const objectParams = { tags: ['zod', 'typescript'], ids: '42', }; const urlParams = new URLSearchParams(); urlParams.append('tags', 'zod'); urlParams.append('tags', 'typescript'); urlParams.append('ids', '42'); console.log(parseSearchParams(schema, objectParams)); console.log(parseSearchParams(schema, urlParams)); /* OUTPUTS: { tags: ['zod', 'typescript'], ids: [42], } */