npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

nuqs-zod-adapter

v1.0.0

Published

A Nuqs adapter to safely bind Zod schemas with query parameters using type safety, debouncing and auto-reset support.

Readme

nuqs-zod-adapter

A nuqs adapter for using zod schemas and it's defaults together without having to repeat code unnecessarily

Fully compatible with zod schemas and defaults

How it will look like:

yourwebsite.com/search?title=cool+video&category=a

(All using Zod schemas & default values from them, 0 nuqs validation)

Features

  • ✅ Infer types directly from Zod schema
  • ✅ Debouncing feature (completely customizable)
  • ✅ Optional reset of other query keys
  • ✅ Compatible with all Nuqs options (shallow, history, etc.)
  • ✅ Parses enums, numbers, booleans, unions, defaults... automatically

Install

npm install nuqs-zod-adapter

Usage example

Let's say you want to create a filter for a search form which also includes category filtering that syncs with the URL using Nuqs, but with proper type safety, debouncing and optional reset of other keys (e.g., reset page on title change) and without having to duplicate the defaults

1. Define your Zod schema

import { z } from 'zod'

export const paramsFields = {
    title: z.string().optional(),
    category: z.enum(['a', 'b', 'c']).default('a'),
}
  • Title: It's optional but not required, which means that it might not exist in the query

  • Category: Also optional, however its default value will be A when the query is empty

2. Use the hook to connect a param to the URL

Once your schema is defined, you can plug individual fields into the useSafeQueryStateFromZod hook. Here's how to do it for the category param:

import { useSafeQueryStateFromZod } from 'nuqs-zod-adapter'
import { paramsFields } from './schema'

const [category, setCategory] = useSafeQueryStateFromZod(
  'category',
  paramsFields.category,
  {
    delay: 200,            // debounce delay (optional)
    resetKeys: ['page'],   // reset other query params when this changes
    shallow: true          // use shallow routing
    // and all the nuqs options available
  }
)

✅ Syncs category with the query string

✅ Applies Zod validation and type inference

✅ Uses "a" as the default value if none is provided

✅ Debounces updates to avoid router spam

✅ Optionally resets other keys like "page"

3. Using it in your component

Once you have category and setCategory, you can bind them directly to a <select> input, radio buttons, or any other component like this:

<select
  value={category}
  onChange={(e) => setCategory(e.target.value as typeof category)}
  className="border px-3 py-2 rounded"
>
  <option value="a">Category A</option>
  <option value="b">Category B</option>
  <option value="c">Category C</option>
</select>

⚠️ Make sure to cast e.target.value to the correct type (e.g. as typeof category) if TypeScript complains.

4. Combine multiple query params

You can use the hook multiple times, once per field, to build a full filter system connected to the URL

Category & Title together

const [title, setTitle] = useSafeQueryStateFromZod(
  'title',
  paramsFields.title,
  {
    delay: 300,
    resetKeys: ['page'],
    shallow: true
  }
)

const [category, setCategory] = useSafeQueryStateFromZod(
  'category',
  paramsFields.category,
  {
    shallow: true
  }
)

Now they will be both synced, if you type a title on the form, it will display on the URL like this:

If there is no title:

  • yourwebsite.com

If there is a title:

  • yourwebsite.com?title=super+title

If there is a title AND a category:

  • yourwebsite.com?title=super+title&category=a

If there is only a category:

  • yourwebsite.com?category=a

Resetting the values

What if you want to reset all the values with a button? Well, it's as simple as adding a "onClick" function and using the exported setters to set the values to their defaults, here is an example:

<button
  onClick={() => {
    setTitle('')
    setCategory('A') // or paramsFields.category._def.defaultValue() if you want to extract it
  }}
  className="px-4 py-2 bg-gray-200 rounded hover:bg-gray-300"
>
  Reset Filters
</button>

As simple as that.

🛠 Contributing

Contributions are welcome! If you have improvements, bug fixes or new ideas, feel free to submit a pull request or open an issue.

👤 Author

Diego Rodríguez
LinkedIn
GitHub