Zustand URL Query String Sync

raw JSON →
0.7.0 verified Thu Apr 23 auth: no javascript

zustand-querystring is a middleware for Zustand that provides declarative synchronization between parts of a Zustand store's state and the URL's query string. This enables persistent and shareable application states directly embedded in the browser's URL. The current stable version is 0.7.0, with ongoing development evidenced by recent frequent releases that include bug fixes and new features. Key differentiators include flexible state selection via the `select` option, support for multiple serialization formats (e.g., `plain`, `readable`, or custom), granular control over how `null` and `undefined` values are handled (`syncNull`, `syncUndefined`), and a powerful bidirectional `map` option for complex transformations between store state and URL representation. It supports both individual query parameters for each state key (`key: false`) or consolidating the entire state into a single query parameter, and offers prefixing for managing multiple stores on the same page.

error Comma-separated arrays not restored from URL (e.g. `filters.gpus_.architecture=Blackwell,Ada` parsed as string)
cause A bug in the 'plain' format parser for dynamic keys where comma-separated values were not correctly split into arrays.
fix
Upgrade zustand-querystring to version 0.6.0 or higher, which includes a fix for this parsing issue.
error Query parameters are double-encoded in URL (e.g., `?state=%2522hello%2522` instead of `?state=%22hello%22`)
cause An issue where URL parameters were encoded twice, leading to incorrect parsing or excessively long URLs.
fix
This issue was fixed in version 0.3.1. Ensure you are using zustand-querystring version 0.3.1 or later.
error Zustand state not showing up in the URL query string, or not restoring correctly from URL
cause Commonly caused by incorrect configuration of the `select` option (not selecting the desired state fields) or a misconfigured `key` option.
fix
Verify that your select function correctly returns true for all state fields you intend to sync. Also, check the key option: key: false uses individual parameters, while key: 'state' (or any string) consolidates state into a single parameter named 'state' (or your chosen string).
error Null or undefined values for state properties are not reflected in the URL and disappear after refresh
cause By default, `zustand-querystring` does not synchronize `null` or `undefined` values to the URL; it treats them as 'clear' operations.
fix
To synchronize null or undefined values, set syncNull: true or syncUndefined: true (or both) in the middleware options: { syncNull: true, syncUndefined: true }.
breaking Version 0.1.0 introduced a breaking change by switching from a proprietary URL encoding format to standard `encodeURIComponent`/`decodeURIComponent`. Existing URLs encoded with pre-0.1.0 versions will no longer be correctly parsed.
fix Re-evaluate how existing URLs are generated and parsed, potentially requiring a one-time migration or handling of legacy URLs if backward compatibility is critical. Ensure all new URLs are encoded with `encodeURIComponent`.
breaking Version 0.4.0 introduced breaking changes to the encoding scheme of the 'readable' format. If you were using the readable format prior to 0.4.0, URLs will no longer be correctly parsed.
fix Update existing 'readable' format URLs or migrate to the newer 'plain' format introduced in v0.5.0, which offers a cleaner, hand-editable URL structure and is generally recommended.
gotcha By default, `null` and `undefined` values are not synced to the URL. Setting a state property to `null` or `undefined` will effectively clear it from the URL and reset it to its initial state value in the store.
fix If you need `null` or `undefined` to be explicitly synchronized to the URL (e.g., as part of a filter state), set the `syncNull: true` or `syncUndefined: true` options in the middleware configuration.
gotcha Prior to v0.6.0, comma-separated arrays in the 'plain' format with dynamic keys were incorrectly restored as a single string instead of an array. For example, `filters.gpus_.architecture=Blackwell,Ada` would parse as `"Blackwell,Ada"`.
fix Upgrade to version 0.6.0 or higher. If upgrading is not immediately possible, consider custom mapping or alternative serialization for array types to ensure correct parsing.
breaking Changing the `key` option from `false` (default, individual query parameters) to a string value (e.g., `key: 'state'`, which consolidates all state into one parameter) will fundamentally change your URL structure. Existing URLs will become incompatible.
fix Decide on a consistent `key` strategy early in development. If you must change it on a live application, implement a migration strategy (e.g., redirecting old URLs, providing a backward-compatible parser) to prevent broken links.
npm install zustand-querystring
yarn add zustand-querystring
pnpm add zustand-querystring

Initializes a Zustand store with the querystring middleware, syncing `search` and `page` state to URL parameters.

import { create } from 'zustand';
import { querystring } from 'zustand-querystring';

interface MyStoreState {
  search: string;
  page: number;
  setSearch: (search: string) => void;
  setPage: (page: number) => void;
}

const useStore = create<MyStoreState>()(
  querystring(
    set => ({
      search: '',
      page: 1,
      setSearch: search => set({ search }),
      setPage: page => set({ page }),
    }),
    {
      // Select which parts of the state to synchronize with the URL
      select: () => ({ search: true, page: true }),
      // Use individual query parameters like '?search=hello&page=2' (default)
      key: false
    },
  ),
);

// To demonstrate usage, you can update the state, which will reflect in the URL
// For example, calling this in a component:
// useStore.getState().setSearch('example-query');
// useStore.getState().setPage(5);

// This will update the URL to something like: ?search=example-query&page=5