nuqsnuqs

Parsers

When using strings is not enough

Search params are strings by default, but chances are your state is more complex than that.

You might want to use numbers, booleans, Dates, objects, arrays, or even custom types. This is where parsers come in.

nuqs provides built-in parsers for the most common types, and allows you to define your own.

Built-in parsers

String

import { parseAsString } from 'nuqs'
Demo loading...

Type-safety tip

parseAsString is a noop: it does not perform any validation when parsing, and will accept any value.

If you’re expecting a certain set of string values, like 'foo' | 'bar', see Literals for ensuring type-runtime safety.

If search params are strings by default, what’s the point of this “parser” ?

It becomes useful if you’re declaring a search params object, and/or you want to use the builder pattern to specify default values and options:

export const searchParamsParsers = {
  q: parseAsString.withDefault('').withOptions({
    shallow: false
  })
}

Numbers

Integers

Transforms the search param string into an integer with parseInt (base 10).

import { parseAsInteger } from 'nuqs'
 
useQueryState('int', parseAsInteger.withDefault(0))
Demo loading...

Floating point

Same as integer, but uses parseFloat under the hood.

import { parseAsFloat } from 'nuqs'
 
useQueryState('float', parseAsFloat.withDefault(0))
Demo loading...

Hexadecimal

Encodes integers in hexadecimal.

import { parseAsHex } from 'nuqs'
 
useQueryState('hex', parseAsHex.withDefault(0x00))
Demo loading...

Going further

Check out the Hex Colors playground for a demo.

Boolean

import { parseAsBoolean } from 'nuqs'
 
useQueryState('bool', parseAsBoolean.withDefault(false))
Demo loading...

Literals

These parsers extend the basic integer and float parsers, but test against some expected valid values, defined as TypeScript literals.

Note

Don’t forget the as const when declaring your expected values.

String literals

import { parseAsStringLiteral } from 'nuqs'
 
// List accepted values
const sortOrder = ['asc', 'desc'] as const
 
// Then pass it to the parser
parseAsStringLiteral(sortOrder)
 
// Optional: extract the type from them
type SortOrder = (typeof sortOrder)[number]; // 'asc' | 'desc'
Demo loading...

Numeric literals

import { parseAsNumberLiteral } from 'nuqs'
 
// List accepted values
const diceSides = [1, 2, 3, 4, 5, 6] as const
 
// Then pass it to the parser
parseAsNumberLiteral(diceSides)

Enums

String enums are a bit more verbose than string literals, but nuqs supports them.

enum Direction {
  up = 'UP',
  down = 'DOWN',
  left = 'LEFT',
  right = 'RIGHT'
}
 
parseAsStringEnum<Direction>(Object.values(Direction))

Note

The query string value will be the value of the enum, not its name (here: ?direction=UP).

Dates & timestamps

There are two parsers that give you a Date object, their difference is on how they encode the value into the query string.

ISO 8601

import { parseAsIsoDateTime } from 'nuqs'

Timestamp

Miliseconds since the Unix epoch.

import { parseAsTimestamp } from 'nuqs'

Arrays

All of the parsers on this page can be used to parse arrays of their respective types.

import { parseAsArrayOf, parseAsInteger } from 'nuqs'
 
parseAsArrayOf(parseAsInteger)
 
// Optionally, customise the separator
parseAsArrayOf(parseAsInteger, ';')

JSON

If primitive types are not enough, you can encode JSON in the query string.

import { parseAsJson } from 'nuqs'
 
// This parser is a function, don't forget to call it:
const [json, setJson] = useQueryState('json', parseAsJson())
 
setJson({ hello: 'world' })

Validation with Zod

Note that by itself, parseAsJson isn’t type-safe, and will return unknown, as the value could be anything.

You can pass it an optional callback argument to validate the parsed data. Using a Zod schema looks like this:

const zodSchema = z.object({
  foo: z.string(),
  bar: z.number()
})
 
const [obj, setObj] = useQueryState('zod', parseAsJson(zodSchema.parse))

Using other validation libraries is possible, as long as they throw an error when the data is invalid.

Making your own parsers

You may wish to customise the rendered query string for your data type. For this, nuqs exposes the createParser function to make your own parsers.

You pass it two functions:

  1. parse: a function that takes a string and returns the parsed value, or null if invalid.
  2. serialize: a function that takes the parsed value and returns a string.
import { createParser } from 'nuqs'
 
const parseAsStarRating = createParser({
  parse(queryValue) {
    const inBetween = queryValue.split('★')
    const isValid = inBetween.length > 1 && inBetween.every(s => s === '')
    if (!isValid) return null
    const numStars = inBetween.length - 1
    return Math.min(5, numStars)
  },
  serialize(value) {
    return Array.from({length: value}, () => '★').join('')
  }
})

Caveat: lossy serializers

If your serializer loses precision or doesn’t accurately represent the underlying state value, you will lose this precision when reloading the page or restoring state from the URL (eg: on navigation).

Example:

const geoCoordParser = {
  parse: parseFloat,
  serialize: v => v.toFixed(4) // Loses precision
}
 
const [lat, setLat] = useQueryState('lat', geoCoordParser)

Here, setting a latitude of 1.23456789 will render a URL query string of lat=1.2345, while the internal lat state will be correctly set to 1.23456789.

Upon reloading the page, the state will be incorrectly set to 1.2345.

Using parsers server-side

You may import parsers from nuqs/server to use them in your server code, as it doesn’t include the 'use client' directive.

import { parseAsString } from 'nuqs/server'

Note

It used to be available under the alias import nuqs/parsers, which will be dropped in the next major version.

On this page