{"_id":"next-url-state","_rev":"10-d4dc97ae3d34205aedbbf36ca036e6af","name":"next-url-state","dist-tags":{"latest":"1.0.9"},"versions":{"1.0.0":{"name":"next-url-state","version":"1.0.0","keywords":["nextjs","react","hooks","url","query-params","search-params","state-management","routing"],"author":{"name":"Michael Holzner","email":"michael.holzner@digitecgalaxus.ch"},"license":"MIT","_id":"next-url-state@1.0.0","maintainers":[{"name":"mnext","email":"web@michaelholzner.ch"}],"homepage":"https://github.com/DigitecGalaxus/next-url-state#readme","bugs":{"url":"https://github.com/DigitecGalaxus/next-url-state/issues"},"dist":{"shasum":"fdcb47d055048f4be58897e1e7297fa65dc5875a","tarball":"https://registry.npmjs.org/next-url-state/-/next-url-state-1.0.0.tgz","fileCount":15,"integrity":"sha512-VEtMvLvPnGOIBfcpb6z7v8fUbHltwTnRScgwU++RAfvO0twaD8Vho30eixc0HwgIkAxWRPxUn374CnChTmtdBQ==","signatures":[{"sig":"MEUCIQDHw4GYBW0/37IFbhkWvbHmTMykPTAdqneNgcP8sWGfoAIgZnqVAWIfOxDYG+dmq4UM8zfpHeau9W2xBGEynSTi0fw=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":196415},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","engines":{"node":">=20.9.0"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js","require":"./dist/index.js"},"./rsc":{"types":"./dist/rsc.d.ts","import":"./dist/rsc.js","default":"./dist/rsc.js","require":"./dist/rsc.js"},"./package.json":"./package.json"},"gitHead":"1c063c24185dfadeef09da9e6d20b3f7c103b882","private":false,"scripts":{"dev":"tsup --watch","lint":"eslint src --ext .ts,.tsx","test":"jest --watch","build":"tsup","release":"changeset publish","test:ci":"jest --ci --coverage","typecheck":"tsc --noEmit"},"_npmUser":{"name":"mnext","email":"web@michaelholzner.ch"},"repository":{"url":"git+https://github.com/DigitecGalaxus/next-url-state.git","type":"git"},"_npmVersion":"10.8.2","description":"React hooks for managing state in URL search parameters with Next.js","directories":{},"sideEffects":false,"_nodeVersion":"20.20.1","publishConfig":{"access":"public"},"typesVersions":{"*":{"*":["dist/index.d.ts"],"rsc":["dist/rsc.d.ts"]}},"_hasShrinkwrap":false,"devDependencies":{"jest":"^30.2.0","next":"^16.1.7","tsup":"^8.0.1","react":"^18.2.0","eslint":"^8.56.0","esbuild":"^0.25.10","ts-jest":"^29.4.5","react-dom":"^18.2.0","typescript":"^5.3.3","@types/jest":"^30.0.0","@types/node":"^20.11.0","@types/react":"^18.2.48","@changesets/cli":"^2.30.0","@testing-library/dom":"^10.0.0","@testing-library/react":"^16.3.0","jest-environment-jsdom":"^30.2.0","@testing-library/jest-dom":"^6.9.1","@typescript-eslint/parser":"^6.19.0","@typescript-eslint/eslint-plugin":"^6.19.0"},"peerDependencies":{"next":">=16.0.0","react":"^18.0.0","react-dom":"^18.0.0"},"_npmOperationalInternal":{"tmp":"tmp/next-url-state_1.0.0_1774441433020_0.9121877805928704","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"next-url-state","version":"1.0.1","keywords":["nextjs","react","hooks","url","query-params","search-params","state-management","routing"],"author":{"name":"Michael Holzner","email":"michael.holzner@digitecgalaxus.ch"},"license":"MIT","_id":"next-url-state@1.0.1","maintainers":[{"name":"mnext","email":"web@michaelholzner.ch"}],"homepage":"https://github.com/DigitecGalaxus/next-url-state#readme","bugs":{"url":"https://github.com/DigitecGalaxus/next-url-state/issues"},"dist":{"shasum":"ac184296c5a452cb209744c68d45c6cf66e1efc8","tarball":"https://registry.npmjs.org/next-url-state/-/next-url-state-1.0.1.tgz","fileCount":15,"integrity":"sha512-E5AURZJhlHbRpifSNp2YUoN0r95xpt/ArC7tpkZw4eOCst1VmSwcrTqZTpwCsqPmnkCEAYN1niQ9JAnxJ9N5gg==","signatures":[{"sig":"MEQCIH9by23RxEHTkxyioWDModIFo7Td9Rx0iV7n/FEt8jEBAiB9Q27aGgNzWIqRpG4prgw/XsJrE8QvPlgRiugynp8CGA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":201225},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js","require":"./dist/index.js"},"./rsc":{"types":"./dist/rsc.d.ts","import":"./dist/rsc.js","default":"./dist/rsc.js","require":"./dist/rsc.js"},"./package.json":"./package.json"},"gitHead":"b9ec22129c31b4dbfc8788d834366e7d04519546","private":false,"scripts":{"dev":"tsup --watch","lint":"eslint src --ext .ts,.tsx","test":"jest --watch","build":"tsup","release":"changeset publish","test:ci":"jest --ci --coverage","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"_npmUser":{"name":"mnext","email":"web@michaelholzner.ch"},"repository":{"url":"git+https://github.com/DigitecGalaxus/next-url-state.git","type":"git"},"_npmVersion":"11.6.1","description":"React hooks for managing state in URL search parameters with Next.js","directories":{},"sideEffects":false,"_nodeVersion":"24.11.0","publishConfig":{"access":"public","provenance":true},"typesVersions":{"*":{"*":["dist/index.d.ts"],"rsc":["dist/rsc.d.ts"]}},"_hasShrinkwrap":false,"devDependencies":{"jest":"^30.2.0","next":"^16.1.7","tsup":"^8.0.1","react":"^18.2.0","eslint":"^8.56.0","esbuild":"^0.25.10","ts-jest":"^29.4.5","react-dom":"^18.2.0","typescript":"^5.3.3","@types/jest":"^30.0.0","@types/node":"^20.11.0","@types/react":"^18.2.48","@changesets/cli":"^2.30.0","@testing-library/dom":"^10.0.0","@testing-library/react":"^16.3.0","jest-environment-jsdom":"^30.2.0","@testing-library/jest-dom":"^6.9.1","@typescript-eslint/parser":"^6.19.0","@testing-library/user-event":"^14.6.1","@typescript-eslint/eslint-plugin":"^6.19.0"},"peerDependencies":{"next":">=13.4.0","react":">=18.0.0","react-dom":">=18.0.0"},"_npmOperationalInternal":{"tmp":"tmp/next-url-state_1.0.1_1777556999184_0.8484234965112498","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"next-url-state","version":"1.0.2","keywords":["nextjs","react","hooks","url","query-params","search-params","state-management","routing"],"author":{"name":"Michael Holzner","email":"michael.holzner@digitecgalaxus.ch"},"license":"MIT","_id":"next-url-state@1.0.2","maintainers":[{"name":"mnext","email":"web@michaelholzner.ch"}],"homepage":"https://github.com/DigitecGalaxus/next-url-state#readme","bugs":{"url":"https://github.com/DigitecGalaxus/next-url-state/issues"},"dist":{"shasum":"760a18c6fc84e184c2ee7e6a49b4c9820e67f912","tarball":"https://registry.npmjs.org/next-url-state/-/next-url-state-1.0.2.tgz","fileCount":15,"integrity":"sha512-gFCC7odNpabXXSjsLhNnfh18FrMPpd4IWfun0HMXsiiP7HDeSPnftqgtq/C1hwtSEBKz1NwMAjjdwpuQ6oJq0g==","signatures":[{"sig":"MEQCIDoIrYpjvGvSnwp2UZhnvW+Pa+u7jrqgoCT6Sqeig/0aAiBfxoJBvD1rVYrK4QLoIyiaQ0M7CIPRIsGJ1XeqRXhQQg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":202223},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js","require":"./dist/index.js"},"./rsc":{"types":"./dist/rsc.d.ts","import":"./dist/rsc.js","default":"./dist/rsc.js","require":"./dist/rsc.js"},"./package.json":"./package.json"},"gitHead":"a2f4a2c6116ce73dfdffd6aaccc880b9a4bafbda","private":false,"scripts":{"dev":"tsup --watch","lint":"eslint src --ext .ts,.tsx","test":"jest --watch","build":"tsup","release":"changeset publish","test:ci":"jest --ci --coverage","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"_npmUser":{"name":"mnext","email":"web@michaelholzner.ch"},"repository":{"url":"git+https://github.com/DigitecGalaxus/next-url-state.git","type":"git"},"_npmVersion":"11.6.1","description":"React hooks for managing state in URL search parameters with Next.js","directories":{},"sideEffects":false,"_nodeVersion":"24.11.0","publishConfig":{"access":"public","provenance":true},"typesVersions":{"*":{"*":["dist/index.d.ts"],"rsc":["dist/rsc.d.ts"]}},"_hasShrinkwrap":false,"devDependencies":{"jest":"^30.2.0","next":"^16.1.7","tsup":"^8.0.1","react":"^18.2.0","eslint":"^8.56.0","esbuild":"^0.25.10","ts-jest":"^29.4.5","react-dom":"^18.2.0","typescript":"^5.3.3","@types/jest":"^30.0.0","@types/node":"^20.11.0","@types/react":"^18.2.48","@changesets/cli":"^2.30.0","@testing-library/dom":"^10.0.0","@testing-library/react":"^16.3.0","jest-environment-jsdom":"^30.2.0","@testing-library/jest-dom":"^6.9.1","@typescript-eslint/parser":"^6.19.0","@testing-library/user-event":"^14.6.1","@typescript-eslint/eslint-plugin":"^6.19.0"},"peerDependencies":{"next":">=13.4.0","react":">=18.0.0","react-dom":">=18.0.0"},"_npmOperationalInternal":{"tmp":"tmp/next-url-state_1.0.2_1777888992522_0.26567042004083263","host":"s3://npm-registry-packages-npm-production"}},"1.0.3":{"name":"next-url-state","version":"1.0.3","keywords":["nextjs","react","hooks","url","query-params","search-params","state-management","routing"],"author":{"name":"Michael Holzner","email":"michael.holzner@digitecgalaxus.ch"},"license":"MIT","_id":"next-url-state@1.0.3","maintainers":[{"name":"mnext","email":"web@michaelholzner.ch"}],"homepage":"https://github.com/DigitecGalaxus/next-url-state#readme","bugs":{"url":"https://github.com/DigitecGalaxus/next-url-state/issues"},"dist":{"shasum":"c61573059e9aa65f0a18397e0f4f050f25491fdb","tarball":"https://registry.npmjs.org/next-url-state/-/next-url-state-1.0.3.tgz","fileCount":15,"integrity":"sha512-9hOas1t3Jgappv3393SHEiYNhRRrbPFoGNnTyXzFNFD55G5Y+yFfTwRJQzJ5N9sYcrRj2A3ZinyFQ5jbO9WTRw==","signatures":[{"sig":"MEYCIQC7d7bKYdRoNZ6bBvhpLiY9uYKTidMrRkBNkztsDnLIAAIhAPiDxTc2LUAMO1+bs+DQEzMrALnJ0FyiR6BBGIc3G0vp","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":204841},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js","require":"./dist/index.js"},"./rsc":{"types":"./dist/rsc.d.ts","import":"./dist/rsc.js","default":"./dist/rsc.js","require":"./dist/rsc.js"},"./package.json":"./package.json"},"gitHead":"80e441781beea68c93679db7aef411ddb65e4a4f","private":false,"scripts":{"dev":"tsup --watch","lint":"eslint src --ext .ts,.tsx","test":"jest --watch","build":"tsup","release":"changeset publish","test:ci":"jest --ci --coverage","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"_npmUser":{"name":"mnext","email":"web@michaelholzner.ch"},"repository":{"url":"git+https://github.com/DigitecGalaxus/next-url-state.git","type":"git"},"_npmVersion":"11.6.1","description":"React hooks for managing state in URL search parameters with Next.js","directories":{},"sideEffects":false,"_nodeVersion":"24.11.0","publishConfig":{"access":"public","provenance":true},"typesVersions":{"*":{"*":["dist/index.d.ts"],"rsc":["dist/rsc.d.ts"]}},"_hasShrinkwrap":false,"devDependencies":{"jest":"^30.2.0","next":"^16.1.7","tsup":"^8.0.1","react":"^18.2.0","eslint":"^8.56.0","esbuild":"^0.25.10","ts-jest":"^29.4.5","react-dom":"^18.2.0","typescript":"^5.3.3","@types/jest":"^30.0.0","@types/node":"^20.11.0","@types/react":"^18.2.48","@changesets/cli":"^2.30.0","@testing-library/dom":"^10.0.0","@testing-library/react":"^16.3.0","jest-environment-jsdom":"^30.2.0","@testing-library/jest-dom":"^6.9.1","@typescript-eslint/parser":"^6.19.0","@testing-library/user-event":"^14.6.1","@typescript-eslint/eslint-plugin":"^6.19.0"},"peerDependencies":{"next":">=13.4.0","react":">=18.0.0","react-dom":">=18.0.0"},"_npmOperationalInternal":{"tmp":"tmp/next-url-state_1.0.3_1777898543359_0.9803817253976006","host":"s3://npm-registry-packages-npm-production"}},"1.0.4":{"name":"next-url-state","version":"1.0.4","keywords":["nextjs","react","hooks","url","query-params","search-params","state-management","routing"],"author":{"name":"Michael Holzner","email":"michael.holzner@digitecgalaxus.ch"},"license":"MIT","_id":"next-url-state@1.0.4","maintainers":[{"name":"mnext","email":"web@michaelholzner.ch"}],"homepage":"https://github.com/DigitecGalaxus/next-url-state#readme","bugs":{"url":"https://github.com/DigitecGalaxus/next-url-state/issues"},"dist":{"shasum":"ef7a16420e0931650909f9be633a9a9fcf5dd4a5","tarball":"https://registry.npmjs.org/next-url-state/-/next-url-state-1.0.4.tgz","fileCount":15,"integrity":"sha512-6wfPXoEyb1iBEL87zNuJ0ZfNeIEMxg7woHKONuLhZqOFTfm/j8CQGbu2IRjGH8S9Of+Z3mWV2rLByOIbuEZuGA==","signatures":[{"sig":"MEQCIHoBK1hHAgXMBMPVos77jxoGYWrZzlkuoCBLEnYo+HpuAiACxxCTBKIjXBFZtm8TKvPE8SVbXcPKCAez+x9Gy09vgg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":206899},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js","require":"./dist/index.js"},"./rsc":{"types":"./dist/rsc.d.ts","import":"./dist/rsc.js","default":"./dist/rsc.js","require":"./dist/rsc.js"},"./package.json":"./package.json"},"gitHead":"b13d0e915d10ee170515df7ab3b1572d9c739713","private":false,"scripts":{"dev":"tsup --watch","lint":"eslint src --ext .ts,.tsx","test":"jest --watch","build":"tsup","release":"changeset publish","test:ci":"jest --ci --coverage","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"_npmUser":{"name":"mnext","email":"web@michaelholzner.ch"},"repository":{"url":"git+https://github.com/DigitecGalaxus/next-url-state.git","type":"git"},"_npmVersion":"11.6.1","description":"React hooks for managing state in URL search parameters with Next.js","directories":{},"sideEffects":false,"_nodeVersion":"24.11.0","publishConfig":{"access":"public","provenance":true},"typesVersions":{"*":{"*":["dist/index.d.ts"],"rsc":["dist/rsc.d.ts"]}},"_hasShrinkwrap":false,"devDependencies":{"jest":"^30.2.0","next":"^16.1.7","tsup":"^8.0.1","react":"^18.2.0","eslint":"^8.56.0","esbuild":"^0.25.10","ts-jest":"^29.4.5","react-dom":"^18.2.0","typescript":"^5.3.3","@types/jest":"^30.0.0","@types/node":"^20.11.0","@types/react":"^18.2.48","@changesets/cli":"^2.30.0","@testing-library/dom":"^10.0.0","@testing-library/react":"^16.3.0","jest-environment-jsdom":"^30.2.0","@testing-library/jest-dom":"^6.9.1","@typescript-eslint/parser":"^6.19.0","@testing-library/user-event":"^14.6.1","@typescript-eslint/eslint-plugin":"^6.19.0"},"peerDependencies":{"next":">=13.4.0","react":">=18.0.0","react-dom":">=18.0.0"},"_npmOperationalInternal":{"tmp":"tmp/next-url-state_1.0.4_1778166367936_0.5703480284628577","host":"s3://npm-registry-packages-npm-production"}},"1.0.5":{"name":"next-url-state","version":"1.0.5","keywords":["nextjs","react","hooks","url","query-params","search-params","state-management","routing"],"author":{"name":"Michael Holzner","email":"michael.holzner@digitecgalaxus.ch"},"license":"MIT","_id":"next-url-state@1.0.5","maintainers":[{"name":"mnext","email":"web@michaelholzner.ch"}],"homepage":"https://github.com/DigitecGalaxus/next-url-state#readme","bugs":{"url":"https://github.com/DigitecGalaxus/next-url-state/issues"},"dist":{"shasum":"161b021f4bae46901d52e20501f2cf652104498d","tarball":"https://registry.npmjs.org/next-url-state/-/next-url-state-1.0.5.tgz","fileCount":15,"integrity":"sha512-7F6w5iDEYFgKHJRvUXesqLH3b9acRSS2dD/olN6QgopAv41kVTGUfXVqyYrxnUpjpwiGbNQzvHhGqFK8GOJMHA==","signatures":[{"sig":"MEYCIQCPDsEhqGJiIPMvUGVKQsUn2qtrliNH4acrBr+3GVmBYgIhAPWeqJbAeqKjM/npHWrKzWeyAmvjXKAJttg4H5Ndehhv","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":210791},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js","require":"./dist/index.js"},"./rsc":{"types":"./dist/rsc.d.ts","import":"./dist/rsc.js","default":"./dist/rsc.js","require":"./dist/rsc.js"},"./package.json":"./package.json"},"gitHead":"0611f3e02e08c1667a1ba5c7bb7097b2b936a356","private":false,"scripts":{"dev":"tsup --watch","lint":"eslint src --ext .ts,.tsx","test":"jest --watch","build":"tsup","release":"changeset publish","test:ci":"jest --ci --coverage","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"_npmUser":{"name":"mnext","email":"web@michaelholzner.ch"},"repository":{"url":"git+https://github.com/DigitecGalaxus/next-url-state.git","type":"git"},"_npmVersion":"11.6.1","description":"React hooks for managing state in URL search parameters with Next.js","directories":{},"sideEffects":false,"_nodeVersion":"24.11.0","publishConfig":{"access":"public","provenance":true},"typesVersions":{"*":{"*":["dist/index.d.ts"],"rsc":["dist/rsc.d.ts"]}},"_hasShrinkwrap":false,"devDependencies":{"jest":"^30.2.0","next":"^16.1.7","tsup":"^8.0.1","react":"^18.2.0","eslint":"^8.56.0","esbuild":"^0.25.10","ts-jest":"^29.4.5","react-dom":"^18.2.0","typescript":"^5.3.3","@types/jest":"^30.0.0","@types/node":"^20.11.0","@types/react":"^18.2.48","@changesets/cli":"^2.30.0","@testing-library/dom":"^10.0.0","@testing-library/react":"^16.3.0","jest-environment-jsdom":"^30.2.0","@testing-library/jest-dom":"^6.9.1","@typescript-eslint/parser":"^6.19.0","@testing-library/user-event":"^14.6.1","@typescript-eslint/eslint-plugin":"^6.19.0"},"peerDependencies":{"next":">=13.4.0","react":">=18.0.0","react-dom":">=18.0.0"},"_npmOperationalInternal":{"tmp":"tmp/next-url-state_1.0.5_1778167622957_0.9233041816532397","host":"s3://npm-registry-packages-npm-production"}},"1.0.6":{"name":"next-url-state","version":"1.0.6","keywords":["nextjs","react","hooks","url","query-params","search-params","state-management","routing"],"author":{"name":"Michael Holzner","email":"michael.holzner@digitecgalaxus.ch"},"license":"MIT","_id":"next-url-state@1.0.6","maintainers":[{"name":"mnext","email":"web@michaelholzner.ch"}],"homepage":"https://github.com/DigitecGalaxus/next-url-state#readme","bugs":{"url":"https://github.com/DigitecGalaxus/next-url-state/issues"},"dist":{"shasum":"a3b65fc23c40ce5d26a13cc5905232c48c01156c","tarball":"https://registry.npmjs.org/next-url-state/-/next-url-state-1.0.6.tgz","fileCount":15,"integrity":"sha512-gXBf60sMo4AIJrmcPm18gZ1kftva+irLpcyTuYrYWPlN+dd8pe7cdxfDGD+ck1RWd5oV5iePKbg1xCLolNl1dg==","signatures":[{"sig":"MEUCIDZuZuFr0vf6sOGoNsqM+RDCYF58a48UGXUIYwRLiJU3AiEA6z6wKMARGIkUCOjfdPwo+h2y3/BshHaq6q8CuIc7rc4=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":211383},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js","require":"./dist/index.js"},"./rsc":{"types":"./dist/rsc.d.ts","import":"./dist/rsc.js","default":"./dist/rsc.js","require":"./dist/rsc.js"},"./package.json":"./package.json"},"gitHead":"c55f5becc20cbc24bff365cd3ffa88a72074b81c","private":false,"scripts":{"dev":"tsup --watch","lint":"eslint src --ext .ts,.tsx","test":"jest --watch","build":"tsup","release":"changeset publish","test:ci":"jest --ci --coverage","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"_npmUser":{"name":"mnext","email":"web@michaelholzner.ch"},"repository":{"url":"git+https://github.com/DigitecGalaxus/next-url-state.git","type":"git"},"_npmVersion":"11.6.1","description":"React hooks for managing state in URL search parameters with Next.js","directories":{},"sideEffects":false,"_nodeVersion":"24.11.0","publishConfig":{"access":"public","provenance":true},"typesVersions":{"*":{"*":["dist/index.d.ts"],"rsc":["dist/rsc.d.ts"]}},"_hasShrinkwrap":false,"devDependencies":{"jest":"^30.2.0","next":"^16.1.7","tsup":"^8.0.1","react":"^18.2.0","eslint":"^8.56.0","esbuild":"^0.25.10","ts-jest":"^29.4.5","react-dom":"^18.2.0","typescript":"^5.3.3","@types/jest":"^30.0.0","@types/node":"^20.11.0","@types/react":"^18.2.48","@changesets/cli":"^2.30.0","@testing-library/dom":"^10.0.0","@testing-library/react":"^16.3.0","jest-environment-jsdom":"^30.2.0","@testing-library/jest-dom":"^6.9.1","@typescript-eslint/parser":"^6.19.0","@testing-library/user-event":"^14.6.1","@typescript-eslint/eslint-plugin":"^6.19.0"},"peerDependencies":{"next":">=13.4.0","react":">=18.0.0","react-dom":">=18.0.0"},"_npmOperationalInternal":{"tmp":"tmp/next-url-state_1.0.6_1778511533592_0.9920050209370956","host":"s3://npm-registry-packages-npm-production"}},"1.0.7":{"name":"next-url-state","version":"1.0.7","keywords":["nextjs","react","hooks","url","query-params","search-params","state-management","routing"],"author":{"name":"Michael Holzner","email":"michael.holzner@digitecgalaxus.ch"},"license":"MIT","_id":"next-url-state@1.0.7","maintainers":[{"name":"mnext","email":"web@michaelholzner.ch"}],"homepage":"https://github.com/DigitecGalaxus/next-url-state#readme","bugs":{"url":"https://github.com/DigitecGalaxus/next-url-state/issues"},"dist":{"shasum":"06b4208af9f503a73e0aa76c84456637791df594","tarball":"https://registry.npmjs.org/next-url-state/-/next-url-state-1.0.7.tgz","fileCount":15,"integrity":"sha512-Eqho1q5sSIIiVeT6LRul9vrLCWTB3H3LZeaj2tJn4q6mRg39bZyCMeiREk3pL3JAL6WVihVHRdimIdTyafgtdQ==","signatures":[{"sig":"MEYCIQC0A6wci3vS8DMTFtYfxYm/Lw1iVxzexhZ+eWnZNzoE7gIhAOgGIs3JyF5UjuIgoqe6TOsxdrvZBTA5cKRtdT/QPYmC","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":220155},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js","require":"./dist/index.js"},"./rsc":{"types":"./dist/rsc.d.ts","import":"./dist/rsc.js","default":"./dist/rsc.js","require":"./dist/rsc.js"},"./package.json":"./package.json"},"gitHead":"d943867496b219a0b584a1374a317960b79b2564","private":false,"scripts":{"dev":"tsup --watch","lint":"eslint src --ext .ts,.tsx","test":"jest --watch","build":"tsup","release":"changeset publish","test:ci":"jest --ci --coverage","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"_npmUser":{"name":"mnext","email":"web@michaelholzner.ch"},"repository":{"url":"git+https://github.com/DigitecGalaxus/next-url-state.git","type":"git"},"_npmVersion":"11.6.1","description":"React hooks for managing state in URL search parameters with Next.js","directories":{},"sideEffects":false,"_nodeVersion":"24.11.0","publishConfig":{"access":"public","provenance":true},"typesVersions":{"*":{"*":["dist/index.d.ts"],"rsc":["dist/rsc.d.ts"]}},"_hasShrinkwrap":false,"devDependencies":{"jest":"^30.2.0","next":"^16.1.7","tsup":"^8.0.1","react":"^18.2.0","eslint":"^8.56.0","esbuild":"^0.25.10","ts-jest":"^29.4.5","react-dom":"^18.2.0","typescript":"^5.3.3","@types/jest":"^30.0.0","@types/node":"^20.11.0","@types/react":"^18.2.48","@changesets/cli":"^2.30.0","@testing-library/dom":"^10.0.0","@testing-library/react":"^16.3.0","jest-environment-jsdom":"^30.2.0","@testing-library/jest-dom":"^6.9.1","@typescript-eslint/parser":"^6.19.0","@testing-library/user-event":"^14.6.1","@typescript-eslint/eslint-plugin":"^6.19.0"},"peerDependencies":{"next":">=13.4.0","react":">=18.0.0","react-dom":">=18.0.0"},"_npmOperationalInternal":{"tmp":"tmp/next-url-state_1.0.7_1778598930265_0.7906032730026478","host":"s3://npm-registry-packages-npm-production"}},"1.0.8":{"name":"next-url-state","version":"1.0.8","keywords":["nextjs","react","hooks","url","query-params","search-params","state-management","routing"],"author":{"name":"Michael Holzner","email":"michael.holzner@digitecgalaxus.ch"},"license":"MIT","_id":"next-url-state@1.0.8","maintainers":[{"name":"mnext","email":"web@michaelholzner.ch"}],"homepage":"https://github.com/DigitecGalaxus/next-url-state#readme","bugs":{"url":"https://github.com/DigitecGalaxus/next-url-state/issues"},"dist":{"shasum":"1e77161884ca4e05224e5bbf1422692c8dfae625","tarball":"https://registry.npmjs.org/next-url-state/-/next-url-state-1.0.8.tgz","fileCount":15,"integrity":"sha512-lrxI22/RraoOtBXuIALMJw5xSSnz8YDxiTOVzylzWvsFf9Sr75X7M+yvu69EiLv2WkSvWde09/z9snegaNT7wQ==","signatures":[{"sig":"MEQCIEYgqdeSKhY0mQ8BZ//5Qg3SMMi48ARA/HQsdOGB2I4zAiAtfNcxjokfVuEfR1TJcjkhebrIBOriX419oWsUWAnUfw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/next-url-state@1.0.8","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":216337},"main":"./dist/index.js","types":"./dist/index.d.ts","module":"./dist/index.mjs","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","default":"./dist/index.js","require":"./dist/index.js"},"./rsc":{"types":"./dist/rsc.d.ts","import":"./dist/rsc.js","default":"./dist/rsc.js","require":"./dist/rsc.js"},"./package.json":"./package.json"},"gitHead":"75f49a347d8430f30fe764e7d1f07cdd77e494a8","private":false,"scripts":{"dev":"tsup --watch","lint":"eslint src --ext .ts,.tsx","test":"jest --watch","build":"tsup","release":"changeset publish","test:ci":"jest --ci --coverage","typecheck":"tsc --noEmit","prepublishOnly":"npm run build"},"_npmUser":{"name":"mnext","email":"web@michaelholzner.ch"},"repository":{"url":"git+https://github.com/DigitecGalaxus/next-url-state.git","type":"git"},"_npmVersion":"10.9.8","description":"React hooks for managing state in URL search parameters with Next.js","directories":{},"sideEffects":false,"_nodeVersion":"22.23.1","publishConfig":{"access":"public","provenance":true},"typesVersions":{"*":{"*":["dist/index.d.ts"],"rsc":["dist/rsc.d.ts"]}},"_hasShrinkwrap":false,"devDependencies":{"jest":"^30.2.0","next":"^16.1.7","tsup":"^8.0.1","react":"^18.2.0","eslint":"^8.56.0","esbuild":"^0.25.10","ts-jest":"^29.4.5","react-dom":"^18.2.0","typescript":"^5.3.3","@types/jest":"^30.0.0","@types/node":"^20.11.0","@types/react":"^18.2.48","@changesets/cli":"^2.30.0","@testing-library/dom":"^10.0.0","@testing-library/react":"^16.3.0","jest-environment-jsdom":"^30.2.0","@testing-library/jest-dom":"^6.9.1","@typescript-eslint/parser":"^6.19.0","@testing-library/user-event":"^14.6.1","@typescript-eslint/eslint-plugin":"^6.19.0"},"peerDependencies":{"next":">=13.4.0","react":">=18.0.0","react-dom":">=18.0.0"},"_npmOperationalInternal":{"tmp":"tmp/next-url-state_1.0.8_1784812173681_0.3450472786245602","host":"s3://npm-registry-packages-npm-production"}},"1.0.9":{"name":"next-url-state","version":"1.0.9","private":false,"description":"React hooks for managing state in URL search parameters with Next.js","author":{"name":"Michael Holzner","email":"michael.holzner@digitecgalaxus.ch"},"license":"MIT","keywords":["nextjs","react","hooks","url","query-params","search-params","state-management","routing"],"repository":{"type":"git","url":"git+https://github.com/DigitecGalaxus/next-url-state.git"},"bugs":{"url":"https://github.com/DigitecGalaxus/next-url-state/issues"},"homepage":"https://github.com/DigitecGalaxus/next-url-state#readme","main":"./dist/index.js","module":"./dist/index.mjs","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.js","default":"./dist/index.js"},"./rsc":{"types":"./dist/rsc.d.ts","import":"./dist/rsc.js","require":"./dist/rsc.js","default":"./dist/rsc.js"},"./package.json":"./package.json"},"typesVersions":{"*":{"rsc":["dist/rsc.d.ts"],"*":["dist/index.d.ts"]}},"sideEffects":false,"scripts":{"build":"tsup","dev":"tsup --watch","lint":"eslint src --ext .ts,.tsx","typecheck":"tsc --noEmit","test":"jest --watch","test:ci":"jest --ci --coverage","prepublishOnly":"npm run build","release":"changeset publish"},"peerDependencies":{"next":">=13.4.0","react":">=18.0.0","react-dom":">=18.0.0"},"devDependencies":{"@changesets/cli":"^2.30.0","@testing-library/dom":"^10.0.0","@testing-library/jest-dom":"^6.9.1","@testing-library/react":"^16.3.0","@testing-library/user-event":"^14.6.1","@types/jest":"^30.0.0","@types/node":"^20.11.0","@types/react":"^18.2.48","@typescript-eslint/eslint-plugin":"^6.19.0","@typescript-eslint/parser":"^6.19.0","esbuild":"^0.25.10","eslint":"^8.56.0","jest":"^30.2.0","jest-environment-jsdom":"^30.2.0","next":"^16.1.7","react":"^18.2.0","react-dom":"^18.2.0","ts-jest":"^29.4.5","tsup":"^8.0.1","typescript":"^5.3.3"},"engines":{"node":">=18"},"publishConfig":{"access":"public","provenance":true},"_id":"next-url-state@1.0.9","gitHead":"49c7f2bd9c222301e3eb50cadd302edb6deb20f6","_nodeVersion":"22.23.2","_npmVersion":"10.9.8","dist":{"integrity":"sha512-ElpDvrAS/I/2tqouv4nEKkfROcB0M4THhzPQOrIMF8AeCWFyeBOvormjn75QdApt+aennOEQid9lp3/n0L76DQ==","shasum":"376fefc28be4d177c95fca21285dc2f2215eb92d","tarball":"https://registry.npmjs.org/next-url-state/-/next-url-state-1.0.9.tgz","fileCount":15,"unpackedSize":220448,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/next-url-state@1.0.9","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQCcm82XxbjWKk4sMuvtxQH2T/1yrVIp4THFo1iTbv99wgIgW1xWdiReZnWnnyLCHTANxVLa9Rt5vwaEe9HaXo8x05I="}]},"_npmUser":{"name":"mnext","email":"web@michaelholzner.ch"},"directories":{},"maintainers":[{"name":"mnext","email":"web@michaelholzner.ch"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/next-url-state_1.0.9_1787139549075_0.7565239002444315"},"_hasShrinkwrap":false}},"time":{"created":"2026-03-25T12:23:52.914Z","modified":"2026-08-19T11:39:09.598Z","1.0.0":"2026-03-25T12:23:53.189Z","1.0.1":"2026-04-30T13:49:59.334Z","1.0.2":"2026-05-04T10:03:12.917Z","1.0.3":"2026-05-04T12:42:23.490Z","1.0.4":"2026-05-07T15:06:08.070Z","1.0.5":"2026-05-07T15:27:03.112Z","1.0.6":"2026-05-11T14:58:53.754Z","1.0.7":"2026-05-12T15:15:30.473Z","1.0.8":"2026-07-23T13:09:33.815Z","1.0.9":"2026-08-19T11:39:09.216Z"},"bugs":{"url":"https://github.com/DigitecGalaxus/next-url-state/issues"},"author":{"name":"Michael Holzner","email":"michael.holzner@digitecgalaxus.ch"},"license":"MIT","homepage":"https://github.com/DigitecGalaxus/next-url-state#readme","keywords":["nextjs","react","hooks","url","query-params","search-params","state-management","routing"],"repository":{"type":"git","url":"git+https://github.com/DigitecGalaxus/next-url-state.git"},"description":"React hooks for managing state in URL search parameters with Next.js","maintainers":[{"name":"mnext","email":"web@michaelholzner.ch"}],"readme":"# next-url-state\n\n> Next.js URL state management that gets out of your way.\n\n[![npm version](https://badge.fury.io/js/next-url-state.svg)](https://www.npmjs.com/package/next-url-state)\n[![npm downloads](https://img.shields.io/npm/dw/next-url-state.svg)](https://www.npmjs.com/package/next-url-state)\n[![GitHub stars](https://img.shields.io/github/stars/DigitecGalaxus/next-url-state.svg)](https://github.com/DigitecGalaxus/next-url-state)\n[![Bundle size](https://img.shields.io/bundlephobia/minzip/next-url-state)](https://bundlephobia.com/package/next-url-state)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\n[Preview (Video)](https://github.com/user-attachments/assets/01f9b244-2258-4ad6-9af5-c79d3487bcff)\n\n**Used in production by:**\n\n[<img src=\"https://github.com/DigitecGalaxus.png\" height=\"40\" alt=\"Digitec Galaxus\" />](https://www.galaxus.ch)\n\n## Table of Contents\n\n- [Why you should use this library?](#why-you-should-use-this-library)\n- [Installation](#installation)\n- [Quick Start](#quick-start)\n- [Migration Guide](#migration-guide)\n- [API Reference](#api-reference)\n- [Options](#options)\n- [How It Works](#how-it-works)\n- [Configuration](#configuration)\n- [TypeScript Support](#typescript-support)\n- [Compatibility](#compatibility)\n- [FAQ / Troubleshooting](#faq--troubleshooting)\n- [Contributing](#contributing)\n- [License](#license)\n\n## Why you should use this library?\n\n### The Problem with Vanilla Next.js\n\nManaging URL state in Next.js requires a lot of boilerplate and comes with several pain points\n\n**Problems:**\n- **Lots of boilerplate** - Manual state synchronization, useEffect hooks, query object spreading\n- **Race conditions** - State and URL can get out of sync during navigation\n- **Performance issues** - Every keystroke triggers a router update, causing re-renders\n- **Type safety** - URL params are always `string | string[] | undefined`, requiring type guards\n- **Complex updates** - Managing multiple parameters requires careful query object manipulation\n- **Router differences** - Different APIs for Pages Router (`next/router`) vs App Router (`next/navigation`)\n\n### The Solution with next-url-state is slim and simple\n\n**Benefits:**\n- ✅ **Minimal code** - One line hook replaces 20+ lines of boilerplate\n- ✅ **Automatic sync** - State and URL stay in sync automatically\n- ✅ **Optimized performance** - Built-in batching ( default: 250ms, configurable ) and optimistic updates\n- ✅ **Type safety & Flexibility** - Support for basic and custom data types, including custom serialization\n- ✅ **Simple API** - Works just like `useState` but with URL persistence\n- ✅ **Router agnostic** - Works with both Pages Router and App Router — hooks have identical API regardless of router\n- ✅ **Zero Dependencies** - Lightweight with only peer dependencies on React and Next.js\n\nThis library handles all the complexity of URL state management, letting you focus on building features instead of wrestling with router APIs.\n\n### How It Compares\n\n| Feature | next-url-state | [nuqs](https://nuqs.47ng.com) | [use-query-params](https://github.com/pbeshai/use-query-params) |\n|---|:---:|:---:|:---:|\n| Pages Router (`/pages`) | ✅ | ✅ | ✅ |\n| App Router (`/app`) | ✅ | ✅ | ⚠️ adapter required |\n| React Server Components | ✅ read-only | ✅ read-only | ❌ |\n| Works like `useState` | ✅ | ✅ | ✅ |\n| Optimistic UI updates | ✅ | ❌ | ❌ |\n| Automatic batching | ✅ | ✅ | ❌ |\n| Custom parse / serialize | ✅ | ✅ | ✅ |\n| TypeScript support | ✅ | ✅ | ✅ |\n| Zero dependencies | ✅ | ❌ | ❌ |\n| Bundle size (min+gzip) | [![](https://img.shields.io/bundlephobia/minzip/next-url-state)](https://bundlephobia.com/package/next-url-state) | [![](https://img.shields.io/bundlephobia/minzip/nuqs)](https://bundlephobia.com/package/nuqs) | [![](https://img.shields.io/bundlephobia/minzip/use-query-params)](https://bundlephobia.com/package/use-query-params) |\n\n> ⚠️ Competitor features reflect best available knowledge — check their docs for the latest.\n\n## Installation\n\n```bash\nnpm install next-url-state\n```\n\n```bash\nyarn add next-url-state\n```\n\n```bash\npnpm add next-url-state\n```\n\n## Quick Start\n\n### 30-Second Start\n\nTwo steps — pick the right provider for your router:\n\n```tsx\n// Step 1 — wrap your app once\n// pages/_app.tsx (Pages Router)\nimport { UrlParamsPagesRouterProvider } from 'next-url-state';\n\nexport default function App({ Component, pageProps }) {\n  return (\n    <UrlParamsPagesRouterProvider>\n      <Component {...pageProps} />\n    </UrlParamsPagesRouterProvider>\n  );\n}\n```\n\n```tsx\n// app/layout.tsx (App Router)\nimport { UrlParamsProvider } from 'next-url-state';\n\nexport default function RootLayout({ children }) {\n  return (\n    <html><body>\n      <UrlParamsProvider>{children}</UrlParamsProvider>\n    </body></html>\n  );\n}\n```\n\n```tsx\n// Step 2 — use it anywhere in both routers, just like useState\n'use client'; // only needed for App Router\nimport { useUrlParam } from 'next-url-state';\n\nfunction Search() {\n  const [query, setQuery] = useUrlParam('q');\n  return <input value={query ?? ''} onChange={e => setQuery(e.target.value)} />;\n}\n```\n\nThat's it. The URL updates automatically. For router-specific setup details see below.\n\n---\n\n### Pages Router Setup\n\n#### 1. Wrap your app with `UrlParamsPagesRouterProvider`\n\n```tsx\n// pages/_app.tsx\nimport { UrlParamsPagesRouterProvider } from 'next-url-state';\n\nconst MyApp = ({ Component, pageProps }) => {\n  return (\n    <UrlParamsPagesRouterProvider>\n      <Component {...pageProps} />\n    </UrlParamsPagesRouterProvider>\n  );\n}\n\nexport default MyApp;\n```\n\n> **Why `UrlParamsPagesRouterProvider` and not `UrlParamsProvider`?**\n>\n> `UrlParamsPagesRouterProvider` is a thin wrapper that reads `router.asPath` from `next/router` and passes it to the provider as the initial server-side path. This means URL parameters are available **during SSR**, so the server and client render identically — no hydration mismatch.\n>\n> `UrlParamsProvider` is intended for **App Router** apps — use it there, not in Pages Router. In a Pages Router app it starts with an empty param set on the server (no access to `next/router`), which causes hydration mismatches.\n\n#### 2. Use the hooks in your components\n\n```tsx\nimport { useUrlParam } from 'next-url-state';\n\nconst SearchComponent = () => {\n  const [query, setQuery] = useUrlParam('q');\n\n  return (\n    <input\n      value={query || ''}\n      onChange={(e) => setQuery(e.target.value)}\n      placeholder=\"Search...\"\n    />\n  );\n}\n```\n\n### App Router Setup\n\n#### 1. Create a client provider component (if only this provider is needed proceed with step 2)\n\n```tsx\n// app/providers.tsx\n'use client';\n\nimport { UrlParamsProvider } from 'next-url-state';\n\nexport const Providers = ({ children }: { children: React.ReactNode }) => {\n  return <UrlParamsProvider>{children}</UrlParamsProvider>;\n}\n```\n\n#### 2. Use it in your root layout\n\n```tsx\n// app/layout.tsx\nimport { Providers } from './providers';\n\nexport default function RootLayout({ children }: { children: React.ReactNode }) {\n  return (\n    <html>\n      <body>\n        {/* UrlParamsProvider can be used directly if no other provider is needed */}\n        <Providers>{children}</Providers> \n      </body>\n    </html>\n  );\n}\n```\n\n#### 3. Use the hooks in your components\n\n```tsx\n// app/search/page.tsx\n'use client';\n\nimport { useUrlParam } from 'next-url-state';\n\nexport default function SearchPage() {\n  const [query, setQuery] = useUrlParam('q');\n\n  return (\n    <input\n      value={query || ''}\n      onChange={(e) => setQuery(e.target.value)}\n      placeholder=\"Search...\"\n    />\n  );\n}\n```\n\n> **Note**: Components using these hooks must be client components (`'use client'`)\n\n### React Server Components\n\nFor React Server Components, use the `createRscAdapter` function to read URL parameters (no writing):\n\n```tsx\n// app/products/page.tsx (Server Component)\nimport { createRscAdapter } from 'next-url-state/rsc';\n\ninterface PageProps {\n  searchParams: Promise<Record<string, string | string[]>>;\n}\n\nexport default async function ProductsPage({ searchParams }: PageProps) {\n  const params = await searchParams;\n  const adapter = createRscAdapter(\n    '/products',\n    new URLSearchParams(params as Record<string, string>)\n  );\n\n  const currentPath = adapter.getCurrentPath();\n  // → \"/products?category=electronics&sort=price\"\n\n  // Note: adapter.updateUrl() is a no-op in RSC\n  // For URL updates, use a Client Component\n\n  return (\n    <div>\n      <p>Current path: {currentPath}</p>\n      {/* Pass data to Client Components for interactivity */}\n    </div>\n  );\n}\n```\n\n> **Note**: `updateUrl()` returns `false` and logs a warning in development mode, since URL updates require client-side JavaScript.\n\n## Migration Guide\n\n### From Next.js Pages Router (the /pages directory)\n\n**Before** — manual state sync, boilerplate, and race-condition-prone:\n\n```tsx\nimport { useRouter } from 'next/router';\nimport { useState, useEffect } from 'react';\n\nconst SearchPage = () => {\n  const router = useRouter();\n  const [search, setSearch] = useState((router.query.q as string) ?? '');\n\n  useEffect(() => {\n    setSearch((router.query.q as string) ?? '');\n  }, [router.query.q]);\n\n  const handleChange = (value: string) => {\n    setSearch(value);\n    router.replace(\n      { query: { ...router.query, q: value } },\n      undefined,\n      { shallow: true }\n    );\n  };\n};\n```\n\n**After** — one line, no boilerplate:\n\n```tsx\nimport { useUrlParam } from 'next-url-state';\n\nconst SearchPage = () => {\n  const [search, setSearch] = useUrlParam('q');\n};\n```\n\nProvider change in `_app.tsx`:\n\n```tsx\n// Before\nimport { useRouter } from 'next/router'; // no provider needed, but lots of manual work\n\n// After\nimport { UrlParamsPagesRouterProvider } from 'next-url-state';\n\nconst MyApp = ({ Component, pageProps }) => (\n  <UrlParamsPagesRouterProvider>\n    <Component {...pageProps} />\n  </UrlParamsPagesRouterProvider>\n);\n```\n\n> **Note**: Use `UrlParamsPagesRouterProvider` (not `UrlParamsProvider`) in Pages Router apps to avoid hydration mismatches. It reads `router.asPath` automatically so URL params are available during SSR.\n\n---\n\n### From Next.js App Router (the /app directory)\n\n**Before** — verbose URL construction on every update:\n\n```tsx\n'use client';\nimport { useSearchParams, useRouter, usePathname } from 'next/navigation';\nimport { useCallback } from 'react';\n\nconst SearchPage = () => {\n  const searchParams = useSearchParams();\n  const router = useRouter();\n  const pathname = usePathname();\n\n  const search = searchParams.get('q');\n\n  const setSearch = useCallback(\n    (value: string) => {\n      const params = new URLSearchParams(searchParams.toString());\n      if (value) params.set('q', value);\n      else params.delete('q');\n      router.replace(`${pathname}?${params.toString()}`);\n    },\n    [searchParams, router, pathname]\n  );\n};\n```\n\n**After**:\n\n```tsx\n'use client';\nimport { useUrlParam } from 'next-url-state';\n\nconst SearchPage = () => {\n  const [search, setSearch] = useUrlParam('q');\n};\n```\n\nProvider change in `layout.tsx`:\n\n```tsx\n// Before — no provider, but each component wires up routing manually\n\n// After\nimport { UrlParamsProvider } from 'next-url-state';\n\nexport default function RootLayout({ children }) {\n  return (\n    <html>\n      <body>\n        <UrlParamsProvider>{children}</UrlParamsProvider>\n      </body>\n    </html>\n  );\n}\n```\n\n---\n\n### From `use-query-params`\n\n**Provider** — simpler setup, no adapter required:\n\n```tsx\n// Before\nimport { QueryParamProvider } from 'use-query-params';\nimport { NextAdapter } from 'next-query-params';\n\n<QueryParamProvider adapter={NextAdapter}>\n  <Component {...pageProps} />\n</QueryParamProvider>\n\n// After (Pages Router)\nimport { UrlParamsPagesRouterProvider } from 'next-url-state';\n\n<UrlParamsPagesRouterProvider>\n  <Component {...pageProps} />\n</UrlParamsPagesRouterProvider>\n```\n\n**Hook equivalents:**\n\n| `use-query-params` | `next-url-state` |\n|---|---|\n| `useQueryParam('q', StringParam)` | `useUrlParam('q')` |\n| `useQueryParam('page', NumberParam)` | `useUrlParam<number>('page', { parse: (v) => parseInt(v ?? '1', 10), serialize: String })` |\n| `useQueryParam('flag', BooleanParam)` | `useUrlParam<boolean>('flag', { parse: (v) => v === 'true', serialize: (v) => v ? 'true' : undefined })` |\n| `useQueryParam('tags', ArrayParam)` | `useUrlParamArray('tags')` |\n| `useQueryParams({ q: StringParam, page: NumberParam })` | `useUrlParams(['q', 'page'])` |\n\n**Example side-by-side:**\n\n```tsx\n// Before\nimport { useQueryParam, useQueryParams, StringParam, NumberParam, ArrayParam } from 'use-query-params';\n\nconst [search, setSearch] = useQueryParam('q', StringParam);\nconst [page, setPage] = useQueryParam('page', NumberParam);\nconst [tags, setTags] = useQueryParam('tags', ArrayParam);\nconst [{ q, page }, setQuery] = useQueryParams({ q: StringParam, page: NumberParam });\n\n// After\nimport { useUrlParam, useUrlParamArray, useUrlParams } from 'next-url-state';\n\nconst [search, setSearch] = useUrlParam('q');\nconst [page, setPage] = useUrlParam<number>('page', { parse: (v) => parseInt(v ?? '1', 10), serialize: String });\nconst [tags, setTags] = useUrlParamArray('tags');\nconst [{ q, page }, setQuery] = useUrlParams(['q', 'page']);\n```\n\n## API Reference\n\n### `useUrlParam`\n\nHook for managing a single URL parameter.\n\n```tsx\nconst [value, setValue] = useUrlParam<T>(paramName, options?);\n```\n\n**Examples:**\n\n```tsx\n// Simple string parameter\nconst [name, setName] = useUrlParam('name');\n\n// With type parsing (number)\nconst [age, setAge] = useUrlParam<number>('age', {\n  parse: (value) => (value ? parseInt(value, 10) : undefined),\n  serialize: (value) => value?.toString(),\n});\n\n// Boolean parameter\nconst [enabled, setEnabled] = useUrlParam<boolean>('enabled', {\n  parse: (value) => value === 'true',\n  serialize: (value) => (value ? 'true' : undefined),\n});\n\n// With history entry (creates browser history entry)\nawait setName('John', { historyEntry: true });\n\n// Without shallow routing (triggers data fetching)\nawait setName('John', { shallow: false });\n```\n\n### `useUrlParamArray`\n\nHook for managing URL parameters with multiple values.\n\n```tsx\nconst [values, setValues] = useUrlParamArray<T>(paramName, options?);\n```\n\n**Example:**\n\n```tsx\n// Multiple tags: /page?tag=react&tag=nextjs&tag=typescript\n// RECOMMENDED: Always use a parser to ensure you get an array\nconst [tags, setTags] = useUrlParamArray<string[]>('tag', {\n  parse: (value) => {\n    if (!value) return [];\n    if (Array.isArray(value)) return value;\n    return [value]; // Single value becomes array\n  },\n});\n\n// Now tags is always string[] (never undefined or string)\nsetTags([...tags, 'new-tag']); // ✅ Safe to use array methods\n\n// Simple usage (may return string | string[] | undefined)\nconst [tags, setTags] = useUrlParamArray('tag');\n// tags could be: undefined, 'single', or ['multiple', 'values']\n```\n\n> **💡 Best Practice**: Always provide a `parse` function to ensure consistent array behavior and avoid `.map()` errors.\n\n### `useUrlParams`\n\nHook for managing multiple URL parameters at once.\n\n```tsx\nconst [params, setParams] = useUrlParams<Keys>(keys?);\n```\n\n**Examples:**\n\n```tsx\n// Subscribe to all URL parameters\nconst [params, setParams] = useUrlParams();\n// params = { q: 'search', page: '1', sort: 'date' }\n\n// Subscribe to specific parameters only\nconst [params, setParams] = useUrlParams(['q', 'page']);\n// Only re-renders when 'q' or 'page' changes\n\n// Update multiple parameters at once\nsetParams({ q: 'new search', page: '1' });\n```\n\n### `useUrlParamsArray`\n\nSimilar to `useUrlParams` but returns arrays for each param.\n\n```tsx\nconst [params, setParams] = useUrlParamsArray<Keys>(keys?);\n```\n\n**Example:**\n\n```tsx\nconst [params, setParams] = useUrlParamsArray(['tags', 'categories']);\n// params = { tags: ['react', 'nextjs'], categories: ['web'] }\n```\n\n### `useUrlParamValue`\n\nRead-only hook for getting a URL parameter value without setter.\n\n```tsx\nconst value = useUrlParamValue<T>(paramName, options?);\n```\n\n**Example:**\n\n```tsx\nconst currentPage = useUrlParamValue<number>('page', {\n  parse: (value) => (value ? parseInt(value, 10) : 1),\n});\n```\n\n## Advanced Usage\n\n### Custom Types with Parsing and Serialization\n\n```tsx\ninterface Filters {\n  minPrice: number;\n  maxPrice: number;\n  category: string;\n}\n\nconst [filters, setFilters] = useUrlParam<Filters>('filters', {\n  parse: (value) => {\n    if (!value) return { minPrice: 0, maxPrice: 1000, category: 'all' };\n    return JSON.parse(value);\n  },\n  serialize: (filters) => JSON.stringify(filters),\n});\n```\n\n### Pagination Example\n\n```tsx\nconst PaginatedList = () => {\n  const [page, setPage] = useUrlParam<number>('page', {\n    parse: (value) => (value ? parseInt(value, 10) : 1),\n    serialize: (value) => value?.toString(),\n  });\n\n  const [itemsPerPage] = useUrlParam<number>('limit', {\n    parse: (value) => (value ? parseInt(value, 10) : 10),\n    serialize: (value) => value?.toString(),\n  });\n\n  return (\n    <div>\n      <div>Page {page}</div>\n      <button onClick={() => setPage(page - 1)} disabled={page <= 1}>\n        Previous\n      </button>\n      <button onClick={() => setPage(page + 1)}>\n        Next\n      </button>\n    </div>\n  );\n}\n```\n\n### Search with Filters\n\n```tsx\nconst ProductSearch = () => {\n  const [search, setSearch] = useUrlParam('q');\n  const [categories, setCategories] = useUrlParamArray('category');\n  const [priceRange, setPriceRange] = useUrlParam('price');\n\n  const [allFilters, setAllFilters] = useUrlParams([\n    'q',\n    'category',\n    'price',\n    'sort',\n  ]);\n\n  const clearFilters = () => {\n    setAllFilters({ q: undefined, category: undefined, price: undefined });\n  };\n\n  return (\n    <div>\n      <input\n        value={search || ''}\n        onChange={(e) => setSearch(e.target.value)}\n      />\n      <button onClick={clearFilters}>Clear Filters</button>\n    </div>\n  );\n}\n```\n\n## Options\n\n### `UrlChangeOptions`\n\nOptions that can be passed to setter functions:\n\n```tsx\ninterface UrlChangeOptions {\n  /**\n   * Shallow routing - doesn't run data fetching methods\n   * @default true\n   */\n  shallow?: boolean;\n\n  /**\n   * Create a browser history entry\n   * @default false\n   */\n  historyEntry?: boolean;\n}\n```\n\n**Example:**\n\n```tsx\n// Create history entry (browser back button will undo this)\nawait setQuery('search term', { historyEntry: true });\n\n// Trigger data fetching (getServerSideProps, etc.)\nawait setQuery('search term', { shallow: false });\n```\n\n## How It Works\n\nThis library provides optimistic updates with URL synchronization:\n\n1. **Immediate UI updates** - When you call a setter, the UI updates immediately\n2. **URL synchronization** - The URL is updated in the background using Next.js Router (next-router or App router)\n3. **Smart batching** - Multiple updates within the debounce window are batched into a single URL change\n4. **Minimal re-renders** - Only components subscribed to changed parameters re-render\n\n## Configuration\n\nLibrary defaults are defined in `src/config.ts` and can be adjusted to tune behavior:\n\n| Constant | Default | Description |\n|---|---|---|\n| `HISTORY_DEBOUNCE_MS` | `250` | Minimum interval (ms) between URL updates that create separate browser history entries. Rapid changes within this window are coalesced into a single entry, preventing the back button from stepping through every keystroke. |\n\n```ts\n// src/config.ts\nexport const HISTORY_DEBOUNCE_MS = 250;\n```\n\n> **Note for contributors**: This is a compile-time constant. To change the debounce for your own needs, clone the repo, edit `src/config.ts`, and build the package locally. End users of the published package cannot configure this at runtime — if you need runtime configurability, please open an issue.\n\n## TypeScript Support\n\nFull TypeScript support with type inference:\n\n```tsx\n// Type is inferred as string | undefined\nconst [name, setName] = useUrlParam('name');\n\n// Explicit typing\nconst [count, setCount] = useUrlParam<number>('count', {\n  parse: (v) => parseInt(v || '0', 10),\n  serialize: (v) => v.toString(),\n});\n\n// Multiple params with specific keys\nconst [params, setParams] = useUrlParams(['search', 'page'] as const);\n// params type: { search: string | undefined; page: string | undefined }\n```\n\n## Compatibility\n\n- **Next.js**: >= 12.0.0 (Pages Router and App Router)\n- **React**: >= 18.0.0\n\n### Router Support\n\nThis library supports **both** Next.js routing systems:\n\n#### ✅ Pages Router (`next/router`)\n- Fully supported with all features\n- Shallow routing enabled by default\n- Use **`UrlParamsPagesRouterProvider`** in `pages/_app.tsx` — it reads `router.asPath` from `next/router` and seeds the provider with the correct path during SSR. This mirrors exactly what Next.js itself does: `router.asPath` is serialized into `__NEXT_DATA__` and available on both server and client, so URL params are consistent across SSR and hydration with zero configuration.\n- `UrlParamsProvider` is intended for App Router — don't use it in Pages Router apps.\n\n#### ✅ App Router (`next/navigation`)\n- Fully supported with all features\n- Uses **`UrlParamsProvider`** in `app/layout.tsx` — internally wraps `useSearchParams()` from `next/navigation` and applies a mounted guard to prevent hydration mismatches. App Router client components are always ready on the client, so no `asPath` seed is needed.\n- Note: App Router doesn't support shallow routing (handled gracefully)\n\n#### ✅ React Server Components (RSC)\n- Read-only access to URL parameters\n- Use `createRscAdapter` from `next-url-state/rsc` for Server Components\n- Setter is a no-op (URL updates require client-side JavaScript)\n\n#### Summary: which provider to use?\n\n| App type | Provider | Why |\n|---|---|---|\n| Pages Router (`/pages`) | `UrlParamsPagesRouterProvider` | Reads `router.asPath` on server — no hydration mismatch |\n| App Router (`/app`) | `UrlParamsProvider` | Wraps `useSearchParams()` with a mounted guard |\n| Both routers — hooks | `useUrlParam`, `useUrlParams`, … | Identical API regardless of router |\n\nSee the [examples](examples/) folder for working demos of all supported router types:\n- [examples/next-app](examples/next-app/) — App Router example (port 3004)\n- [examples/pages-router](examples/pages-router/) — Pages Router example (port 3005)\n\n## FAQ / Troubleshooting\n\n**Why not just use `useSearchParams()` directly?**\n\n`useSearchParams` (App Router) and `router.query` (Pages Router) require you to wire up reading, writing, and URL construction yourself every single time. For a single param that means three hooks, manual `URLSearchParams` construction, careful spreading to preserve other params, and no batching. `next-url-state` reduces all of that to one line that behaves like `useState`.\n\n---\n\n**Does this work with SSR / Server-Side Rendering?**\n\nYes — in two ways:\n- **Pages Router**: use `UrlParamsPagesRouterProvider` in `pages/_app.tsx`. It reads `router.asPath` from `next/router` on the server, so URL params are seeded correctly during SSR. The server and client render identically — no hydration mismatch.\n- **App Router**: use `UrlParamsProvider` in `app/layout.tsx`. It wraps `useSearchParams()` with a mounted guard, which is the standard hydration-safe pattern for App Router client components.\n- **React Server Components**: use `createRscAdapter` from `next-url-state/rsc` for read-only access. Setters are no-ops in RSC since URL updates require client-side JavaScript.\n\n---\n\n**I'm getting a React hydration mismatch — server and client render differently for components that read URL params.**\n\nThis happens in Pages Router apps when `UrlParamsProvider` is used instead of `UrlParamsPagesRouterProvider`. `UrlParamsProvider` cannot access `next/router` on the server, so it starts with empty URL params — meaning a component that opens an accordion when `?section=true` is present will render closed on the server but open on the client.\n\nFix: replace `UrlParamsProvider` with `UrlParamsPagesRouterProvider` in `pages/_app.tsx`:\n\n```tsx\n// Before\nimport { UrlParamsProvider } from 'next-url-state';\n// ...\n<UrlParamsProvider>{children}</UrlParamsProvider>\n\n// After\nimport { UrlParamsPagesRouterProvider } from 'next-url-state';\n// ...\n<UrlParamsPagesRouterProvider>{children}</UrlParamsPagesRouterProvider>\n```\n\n---\n\n**How does batching work exactly?**\n\nEvery setter call updates the UI **immediately** (optimistic update), but the actual URL write is debounced. All setter calls that happen within the `HISTORY_DEBOUNCE_MS` window (default 250 ms) are merged into a single `router.replace` / `router.push` call. This means typing into a search input doesn't flood the browser history with one entry per keystroke — only a single history entry is created once the user pauses. The debounce is [configurable](src/config.ts).\n\n---\n\n**Does batching work across multiple components?**\n\nYes. All hooks share the same internal store via `UrlParamsProvider`. Updates from different components within the same debounce window are merged into one URL change.\n\n---\n\n**Why do I need `UrlParamsProvider`?**\n\nThe provider creates the shared reactive store that all hooks read from and write to. Without it, hooks can't share state between components or batch their updates together. If you forget it, hooks will throw an error pointing you to add the provider.\n\n---\n\n**What happens when I set a value to `undefined`?**\n\nThe parameter is removed from the URL entirely, keeping it clean. For example, `setSearch(undefined)` turns `?q=hello&page=2` into `?page=2`.\n\n---\n\n**Does this work with the browser's Back / Forward buttons?**\n\nYes. When `historyEntry: true` is passed to a setter, a new browser history entry is created and the back button will undo that change. By default (`historyEntry: false`) the URL is replaced without adding a history entry, which is the right default for things like search inputs.\n\n---\n\n**Can I use this outside of Next.js?**\n\nNo. The library depends on Next.js routing APIs (`next/router` for the Pages Router, `next/navigation` for the App Router) and is not designed for plain React or other frameworks.\n\n---\n\n**How do I set up next-url-state in tests (Jest / Vitest) for a Pages Router project?**\n\nIn a jsdom test environment, `window` exists but `window.__NEXT_DATA__` is not set. Without it, the library cannot detect that it is running inside a Pages Router app and falls back to the App Router adapter, which causes errors like:\n\n```\nError: invariant expected app router to be mounted\n```\n\nAdd the following to your test setup file (e.g. `vitest.setup.ts` or `jest.setup.ts`):\n\n```ts\nif (typeof window !== \"undefined\") {\n  // Signal Pages Router to next-url-state\n  window.__NEXT_DATA__ ??= {\n    props: {},\n    page: \"/\",\n    query: {},\n    buildId: \"test\",\n  };\n}\n```\n\nThis mirrors what Next.js sets in production and lets the library pick the correct Pages Router adapter. No equivalent setup is needed for App Router projects.\n\n## Contributing\n\nContributions are welcome!\n\nThe [contributing guide](CONTRIBUTING.md) helps you get started with setting up the development environment and explains the development workflow.\n\n## License\n\n**next-url-state** is licensed under the [MIT License](https://github.com/DigitecGalaxus/next-url-state/blob/main/LICENSE).\n\n## Acknowledgments\n\nThis library was inspired by the need for better URL state management in Next.js applications.\n","readmeFilename":"README.md"}