@@ -3,6 +3,126 @@ title: Server-Side usage
3
3
description : Type-safe search params on the server
4
4
---
5
5
6
+ ## Loaders
7
+
8
+ To parse search params server-side, you can use a _ loader_ function.
9
+
10
+ You create one using the ` createLoader{:ts} ` function, by passing it your search params
11
+ descriptor object:
12
+
13
+ ``` tsx title="searchParams.tsx"
14
+ // [!code word:createLoader]
15
+ import { parseAsFloat , createLoader } from ' nuqs/server'
16
+
17
+ // Describe your search params, and reuse this in useQueryStates / createSerializer:
18
+ export const coordinatesSearchParams = {
19
+ latitude: parseAsFloat .withDefault (0 )
20
+ longitude : parseAsFloat .withDefault (0 )
21
+ }
22
+
23
+ export const loadSearchParams = createLoader (coordinatesSearchParams )
24
+ ```
25
+
26
+ Here, ` loadSearchParams{:ts} ` is a function that parses search params and returns
27
+ state variables to be consumed server-side (the same state type that [ ` useQueryStates{:ts} ` ] ( /docs/batching ) returns).
28
+
29
+ <Tabs items = { [" Next.js (app router)" , " Next.js (pages router)" , " API routes" , " Remix / React Router" , " React / client-side" ]} >
30
+
31
+ ``` tsx tab="Next.js (app router)" title="app/page.tsx"
32
+ // [!code word:loadSearchParams]
33
+ import { loadSearchParams } from ' ./search-params'
34
+ import type { SearchParams } from ' nuqs/server'
35
+
36
+ type PageProps = {
37
+ searchParams: Promise < SearchParams>
38
+ }
39
+
40
+ export default async function Page ({ searchParams }: PageProps ) {
41
+ const { latitude , longitude } = await loadSearchParams (searchParams)
42
+ return < Map
43
+ lat= {latitude}
44
+ lng= {longitude}
45
+ / >
46
+
47
+ // Pro tip: you don't *have* to await the result.
48
+ // Pass the Promise object to children components wrapped in <Suspense>
49
+ // to benefit from PPR / dynamicIO and serve a static outer shell
50
+ // immediately, while streaming in the dynamic parts that depend on
51
+ // the search params when they become available.
52
+ }
53
+ ```
54
+
55
+ ``` ts tab="Next.js (pages router)" title="pages/index.tsx"
56
+ // [!code word:loadSearchParams]
57
+ import type { GetServerSidePropsContext } from ' next'
58
+
59
+ export async function getServerSideProps ({ query }: GetServerSidePropsContext ) {
60
+ const { latitude , longitude } = loadSearchParams (query)
61
+ // Do some server-side calculations with the coordinates
62
+ return {
63
+ props: { ... }
64
+ }
65
+ }
66
+ ```
67
+
68
+ ``` tsx tab="Remix / React Router" title="app/routes/_index.tsx"
69
+ // [!code word:loadSearchParams]
70
+ export function loader({ request }: LoaderFunctionArgs ) {
71
+ const { latitude, longitude } = loadSearchParams (request ) // request.url works too
72
+ // Do some server-side calculations with the coordinates
73
+ return ...
74
+ }
75
+ ```
76
+
77
+ ``` tsx tab="React / client-side"
78
+ // Note: you can also use this client-side (or anywhere, really),
79
+ // for a one-off parsing of non-reactive search params:
80
+
81
+ loadSearchParams (' https://example.com?latitude=42&longitude=12' )
82
+ loadSearchParams (location .search )
83
+ loadSearchParams (new URL (... ))
84
+ loadSearchParams (new URLSearchParams (... ))
85
+ ```
86
+
87
+ ``` tsx tab="API routes"
88
+ // App router, eg: app/api/location/route.ts
89
+ export async function GET(request : Request ) {
90
+ const { latitude, longitude } = loadSearchParams (request )
91
+ // ...
92
+ }
93
+
94
+ // Pages router, eg: pages/api/location.ts
95
+ import type { NextApiRequest , NextApiResponse } from ' next'
96
+ export default function handler(
97
+ request : NextApiRequest ,
98
+ response : NextApiResponse
99
+ ) {
100
+ const { latitude, longitude } = loadSearchParams (request .query )
101
+ }
102
+ ```
103
+
104
+ </Tabs >
105
+
106
+ <Callout type = " warn" title = " Note" >
107
+ Loaders ** don't validate** your data. If you expect positive integers
108
+ or JSON-encoded objects of a particular shape, you'll need to feed the result
109
+ of the loader to a schema validation library, like [ Zod] ( https://zod.dev ) .
110
+
111
+ Built-in validation support is coming. [ Read the RFC] ( https://github.com/47ng/nuqs/discussions/446 ) .
112
+ Alternatively, you can build validation into [ custom parsers] ( /docs/parsers/making-your-own ) .
113
+ </Callout >
114
+
115
+ The loader function will accept the following input types to parse search params from:
116
+ - A string containing a fully qualified URL: ` https://example.com/?foo=bar `
117
+ - A string containing just search params: ` ?foo=bar ` (like ` location.search{:ts} ` )
118
+ - A ` URL{:ts} ` object
119
+ - A ` URLSearchParams{:ts} ` object
120
+ - A ` Request{:ts} ` object
121
+ - A ` Record<string, string | string[] | undefined>{:ts} ` (eg: ` { foo: 'bar' }{:ts} ` )
122
+ - A ` Promise{:ts} ` of any of the above, in which case it also returns a Promise.
123
+
124
+ ## Cache
125
+
6
126
<Callout >
7
127
This feature is available for Next.js only.
8
128
</Callout >
@@ -11,13 +131,8 @@ If you wish to access the searchParams in a deeply nested Server Component
11
131
(ie: not in the Page component), you can use ` createSearchParamsCache{:ts} `
12
132
to do so in a type-safe manner.
13
133
14
- <Callout type = " warn" title = " Note" >
15
- Parsers ** don't validate** your data. If you expect positive integers
16
- or JSON-encoded objects of a particular shape, you'll need to feed the result
17
- of the parser to a schema validation library, like [ Zod] ( https://zod.dev ) .
18
-
19
- Built-in validation support is coming. [ Read the RFC] ( https://github.com/47ng/nuqs/discussions/446 )
20
- </Callout >
134
+ Think of it as a loader combined with a way to propagate the parsed values down
135
+ the RSC tree, like Context would on the client.
21
136
22
137
``` ts title="searchParams.ts"
23
138
import {
0 commit comments