diff --git a/README.md b/README.md
index ea44e86f2..715b88d9b 100644
--- a/README.md
+++ b/README.md
@@ -654,12 +654,9 @@ to do so in a type-safe manner.
```tsx
// searchParams.ts
-import {
- createSearchParamsCache,
- parseAsInteger,
- parseAsString
-} from 'nuqs/server'
-// Note: import from 'nuqs/server' to avoid the "use client" directive
+import { createSearchParamsCache } from 'nuqs/server/cache'
+import { parseAsInteger, parseAsString } from 'nuqs/server'
+// Note: import parsers from 'nuqs/server' to avoid the "use client" directive
export const searchParamsCache = createSearchParamsCache({
// List your search param keys and associated parsers here:
@@ -701,7 +698,8 @@ parser declaration with `useQueryStates` for type-safety in client components:
```tsx
// searchParams.ts
-import { parseAsFloat, createSearchParamsCache } from 'nuqs/server'
+import { parseAsFloat } from 'nuqs/server'
+import { createSearchParamsCache } from 'nuqs/server/cache'
export const coordinatesParsers = {
lat: parseAsFloat.withDefault(45.18),
diff --git a/errors/NUQS-500.md b/errors/NUQS-500.md
index c04571acc..4eeacf54d 100644
--- a/errors/NUQS-500.md
+++ b/errors/NUQS-500.md
@@ -22,12 +22,8 @@ Run the `parse` method and feed it the page's `searchParams`:
```tsx
// page.tsx
-import {
- createSearchParamsCache,
- parseAsInteger,
- parseAsString,
- type SearchParams
-} from 'nuqs/server'
+import { parseAsInteger, parseAsString, type SearchParams } from 'nuqs/server'
+import { createSearchParamsCache } from 'nuqs/server/cache'
const cache = createSearchParamsCache({
q: parseAsString,
diff --git a/packages/docs/content/docs/server-side.mdx b/packages/docs/content/docs/server-side.mdx
index d5b33625d..037386554 100644
--- a/packages/docs/content/docs/server-side.mdx
+++ b/packages/docs/content/docs/server-side.mdx
@@ -124,7 +124,7 @@ The loader function will accept the following input types to parse search params
## Cache
- This feature is available for Next.js only.
+ The `next/server/cache` feature is available for Next.js app router only.
If you wish to access the searchParams in a deeply nested Server Component
@@ -135,12 +135,9 @@ Think of it as a loader combined with a way to propagate the parsed values down
the RSC tree, like Context would on the client.
```ts title="searchParams.ts"
-import {
- createSearchParamsCache,
- parseAsInteger,
- parseAsString
-} from 'nuqs/server'
-// Note: import from 'nuqs/server' to avoid the "use client" directive
+import { createSearchParamsCache } from 'nuqs/server/cache'
+import { parseAsInteger, parseAsString } from 'nuqs/server'
+// Note: import parsers from 'nuqs/server' to avoid the "use client" directive
export const searchParamsCache = createSearchParamsCache({
// List your search param keys and associated parsers here:
@@ -176,6 +173,15 @@ function Results() {
}
```
+
+ The cache feature is also accessible from `nuqs/server` in nuqs@^2, but
+ will be removed from that import in nuqs@3.0.0.
+ Please update your imports to `nuqs/server/cache` for a smoother transition.
+
+ This is to allow non-Next.js server code to use the `nuqs/server` import
+ without having to install React canary for the `cache` function.
+
+
The cache will only be valid for the current page render
(see React's [`cache`](https://react.dev/reference/react/cache) function).
@@ -183,10 +189,8 @@ Note: the cache only works for **server components**, but you may share your
parser declaration with `useQueryStates` for type-safety in client components:
```ts title="searchParams.ts"
-import {
- parseAsFloat,
- createSearchParamsCache
-} from 'nuqs/server'
+import { parseAsFloat } from 'nuqs/server'
+import { createSearchParamsCache } from 'nuqs/server/cache'
export const coordinatesParsers = {
lat: parseAsFloat.withDefault(45.18),
diff --git a/packages/docs/src/app/(pages)/stats/searchParams.ts b/packages/docs/src/app/(pages)/stats/searchParams.ts
index f14a0ad06..b1537a080 100644
--- a/packages/docs/src/app/(pages)/stats/searchParams.ts
+++ b/packages/docs/src/app/(pages)/stats/searchParams.ts
@@ -1,4 +1,5 @@
-import { createSearchParamsCache, parseAsStringLiteral } from 'nuqs/server'
+import { parseAsStringLiteral } from 'nuqs/server'
+import { createSearchParamsCache } from 'nuqs/server/cache'
export const pkgOptions = ['nuqs', 'next-usequerystate', 'both'] as const
export const pkgParser = parseAsStringLiteral(pkgOptions).withDefault('both')
diff --git a/packages/docs/src/app/playground/(demos)/pagination/searchParams.ts b/packages/docs/src/app/playground/(demos)/pagination/searchParams.ts
index 94fe32f48..235500cfe 100644
--- a/packages/docs/src/app/playground/(demos)/pagination/searchParams.ts
+++ b/packages/docs/src/app/playground/(demos)/pagination/searchParams.ts
@@ -1,9 +1,9 @@
import {
- createSearchParamsCache,
createSerializer,
parseAsInteger,
parseAsStringLiteral
} from 'nuqs/server'
+import { createSearchParamsCache } from 'nuqs/server/cache'
export const renderingOptions = ['server', 'client'] as const
export type RenderingOptions = (typeof renderingOptions)[number]
diff --git a/packages/e2e/next/src/app/app/cache/searchParams.ts b/packages/e2e/next/src/app/app/cache/searchParams.ts
index 91ecbe9a1..ec73d6120 100644
--- a/packages/e2e/next/src/app/app/cache/searchParams.ts
+++ b/packages/e2e/next/src/app/app/cache/searchParams.ts
@@ -1,10 +1,10 @@
import {
- createSearchParamsCache,
parseAsBoolean,
- parseAsInteger,
parseAsIndex,
+ parseAsInteger,
parseAsString
} from 'nuqs/server'
+import { createSearchParamsCache } from 'nuqs/server/cache'
export const parsers = {
str: parseAsString,
diff --git a/packages/e2e/next/src/app/app/push/searchParams.ts b/packages/e2e/next/src/app/app/push/searchParams.ts
index 26e0548b2..5de667f15 100644
--- a/packages/e2e/next/src/app/app/push/searchParams.ts
+++ b/packages/e2e/next/src/app/app/push/searchParams.ts
@@ -1,4 +1,5 @@
-import { createSearchParamsCache, parseAsInteger } from 'nuqs/server'
+import { parseAsInteger } from 'nuqs/server'
+import { createSearchParamsCache } from 'nuqs/server/cache'
export const parser = parseAsInteger.withDefault(0).withOptions({
history: 'push'
diff --git a/packages/e2e/next/src/app/app/rewrites/destination/searchParams.ts b/packages/e2e/next/src/app/app/rewrites/destination/searchParams.ts
index c1b536be2..cad0729a3 100644
--- a/packages/e2e/next/src/app/app/rewrites/destination/searchParams.ts
+++ b/packages/e2e/next/src/app/app/rewrites/destination/searchParams.ts
@@ -1,4 +1,5 @@
-import { createSearchParamsCache, parseAsString } from 'nuqs/server'
+import { parseAsString } from 'nuqs/server'
+import { createSearchParamsCache } from 'nuqs/server/cache'
export const searchParams = {
injected: parseAsString.withDefault('null'),
diff --git a/packages/e2e/next/tsconfig.json b/packages/e2e/next/tsconfig.json
index 7d21f37f3..a4ef95503 100644
--- a/packages/e2e/next/tsconfig.json
+++ b/packages/e2e/next/tsconfig.json
@@ -6,7 +6,7 @@
"alwaysStrict": false, // Don't emit "use strict" to avoid conflicts with "use client"
// Modules
"module": "ESNext",
- "moduleResolution": "node",
+ "moduleResolution": "bundler",
"resolveJsonModule": true,
// Language & Environment
"target": "ESNext",
diff --git a/packages/nuqs/package.json b/packages/nuqs/package.json
index fbf08dbbb..2b6485bf3 100644
--- a/packages/nuqs/package.json
+++ b/packages/nuqs/package.json
@@ -36,6 +36,9 @@
"dist/",
"server.d.ts",
"testing.d.ts",
+ "server/cache.d.ts",
+ "server/serializer.d.ts",
+ "server/parsers.d.ts",
"adapters/react.d.ts",
"adapters/next.d.ts",
"adapters/next/app.d.ts",
@@ -65,7 +68,16 @@
},
"./testing": {
"types": "./dist/testing.d.ts",
- "import": "./dist/testing.js",
+ "import": "./dist/testing.js"
+ },
+ "./server/cache": {
+ "types": "./dist/server/cache.d.ts",
+ "import": "./dist/server/cache.js",
+ "require": "./esm-only.cjs"
+ },
+ "./server/temporary-react-agnostic": {
+ "types": "./dist/server/temporary-react-agnostic.d.ts",
+ "import": "./dist/server/temporary-react-agnostic.js",
"require": "./esm-only.cjs"
},
"./adapters/react": {
diff --git a/packages/nuqs/server/README.md b/packages/nuqs/server/README.md
new file mode 100644
index 000000000..6c226eba3
--- /dev/null
+++ b/packages/nuqs/server/README.md
@@ -0,0 +1,9 @@
+Why just the cache here?
+
+Those "top-level" .d.ts files are used to help projects with `moduleResolution: 'node'`
+resolve the correct imports.
+
+The other import under server, `nuqs/server/temporary-react-agnostic`
+is temporary (as it says on the tin) and will be removed in nuqs@3.0.0.
+
+Also, nuqs@3.0.0 will require a `moduleResolution: 'bundler' | 'nodeNext` setting in your tsconfig.json.
diff --git a/packages/nuqs/server/cache.d.ts b/packages/nuqs/server/cache.d.ts
new file mode 100644
index 000000000..c59f78613
--- /dev/null
+++ b/packages/nuqs/server/cache.d.ts
@@ -0,0 +1,13 @@
+// This file is needed for projects that have `moduleResolution` set to `node`
+// in their tsconfig.json to be able to `import {} from 'nuqs/server/cache'`.
+// Other module resolutions strategies will look for the `exports` in `package.json`,
+// but with `node`, TypeScript will look for a .d.ts file with that name at the
+// root of the package.
+
+export { createSearchParamsCache } from './dist/server/cache'
+export type {
+ HistoryOptions,
+ Nullable,
+ Options,
+ SearchParams
+} from './dist/server/cache'
diff --git a/packages/nuqs/src/cache.ts b/packages/nuqs/src/cache.ts
index 7cc2a1306..30b06eb28 100644
--- a/packages/nuqs/src/cache.ts
+++ b/packages/nuqs/src/cache.ts
@@ -1,5 +1,4 @@
-// @ts-ignore
-import { cache } from 'react'
+import * as React from 'react'
import type { SearchParams, UrlKeys } from './defs'
import { error } from './errors'
import { createLoader } from './loader'
@@ -27,7 +26,7 @@ export function createSearchParamsCache(
// whereas a simple object would be bound to the lifecycle of the process,
// which may be reused between requests in a serverless environment
// (warm lambdas on Vercel or AWS).
- const getCache = cache<() => Cache>(() => ({
+ const getCache = React.cache<() => Cache>(() => ({
searchParams: {}
}))
diff --git a/packages/nuqs/src/index.server.cache.ts b/packages/nuqs/src/index.server.cache.ts
new file mode 100644
index 000000000..c7dd671cf
--- /dev/null
+++ b/packages/nuqs/src/index.server.cache.ts
@@ -0,0 +1 @@
+export { createSearchParamsCache } from './cache'
diff --git a/packages/nuqs/src/index.server.ts b/packages/nuqs/src/index.server.ts
index 66bdf5c0e..6aa0ed55e 100644
--- a/packages/nuqs/src/index.server.ts
+++ b/packages/nuqs/src/index.server.ts
@@ -1,4 +1,12 @@
-export { createSearchParamsCache } from './cache'
+export {
+ /** @deprecated Import createSearchParamsCache from 'nuqs/server/cache' instead.
+ *
+ * This export will be removed from 'nuqs/server' in nuqs@3.0.0,
+ * to allow non-Next.js server code to use the parsers, serializeres and other
+ * server-side utilities without depending on React canary for the `cache` function.
+ */
+ createSearchParamsCache
+} from './cache'
export type {
HistoryOptions,
Nullable,
diff --git a/packages/nuqs/src/index.temporary-react-agnostic.ts b/packages/nuqs/src/index.temporary-react-agnostic.ts
new file mode 100644
index 000000000..ce2da4f51
--- /dev/null
+++ b/packages/nuqs/src/index.temporary-react-agnostic.ts
@@ -0,0 +1,15 @@
+export type {
+ HistoryOptions,
+ Nullable,
+ Options,
+ SearchParams,
+ UrlKeys
+} from './defs'
+export {
+ createLoader,
+ type LoaderFunction,
+ type LoaderInput,
+ type LoaderOptions
+} from './loader'
+export * from './parsers'
+export { createSerializer } from './serializer'
diff --git a/packages/nuqs/tests/cache.test-d.ts b/packages/nuqs/tests/cache.test-d.ts
index 94acd3646..a420deff0 100644
--- a/packages/nuqs/tests/cache.test-d.ts
+++ b/packages/nuqs/tests/cache.test-d.ts
@@ -1,10 +1,6 @@
import { assertType, describe, expectTypeOf, it } from 'vitest'
-import {
- createSearchParamsCache,
- parseAsBoolean,
- parseAsInteger,
- parseAsString
-} from '../dist/server'
+import { parseAsBoolean, parseAsInteger, parseAsString } from '../dist/server'
+import { createSearchParamsCache } from '../dist/server/cache'
describe('types/cache', () => {
const cache = createSearchParamsCache({
diff --git a/packages/nuqs/tsup.config.ts b/packages/nuqs/tsup.config.ts
index 50dddbf1c..2c7e8ca5b 100644
--- a/packages/nuqs/tsup.config.ts
+++ b/packages/nuqs/tsup.config.ts
@@ -35,7 +35,9 @@ const entrypoints = {
},
server: {
server: 'src/index.server.ts',
- testing: 'src/testing.ts'
+ testing: 'src/testing.ts',
+ 'server/cache': 'src/index.server.cache.ts',
+ 'server/temporary-react-agnostic': 'src/index.temporary-react-agnostic.ts'
}
}