Custom Search Param Serialization
Hi, I’m running into an issue with search param serialization in TanStack Router. When I pass arrays into search, the URL looks like this:
That’s the array JSON-encoded into a single query param value. What I’d like instead is the more standard repeated-keys format:
I tried following the docs with query-string:
I'm using zod to validate search params in my routes:
But the problem is that the value passed into stringifySearchWith isn’t an array. Instead I’m seeing objects with only number–value pairs like
{0: "DNK", 1: "FIN"}
. That means they end up in the URL as ?country=0%3DFIN
. I don’t even have access to the original key.
This break my validation logic where array is expected:
What’s the recommended way in TanStack Router to produce repeated query keys (?country=DNK&country=FIN) and parse them back into arrays for search params? Any help here would be appreciated 🙏25 Replies
adverse-sapphire•4w ago
You might have better success by doing
stringifySearchWith
iterates over each key:value pair and maps the value using the stringify function you pass in, but you dont want a 1:1 mapping, you want 1 key (your array) to map to multiple keys (all with the same name of country
)
i also recommend using the bracket
array format instead, as this will lead to some uncertainty in some cases, what if you have an array of 1 item? you'd set only one ?country=ONE
then when you need to parse it back, do you parse it as a string or as an array?wise-whiteOP•4w ago
Thank you for the quick response @ferretwithabéret
I'm migrating from React Router to TanStack Router and I’d like my clients’ existing bookmarks to keep working after the migration. So I’m looking for exact-match URLs that contain separate key–value pairs, for example:
route?country=DNK&country=FIN
It seems to be working almost like that, but for some reason I need to manually return the ? symbol as well. Otherwise I end up with:: routecountry=DNK&country=FIN&page=2
. Is that expected behavior??
This is what worked for me:
And then in my schema I have to transform a string into a string array:
I suspect this might be doing more than it should just to achieve the desired result, and I may have something off here. Wdyt? 🤔adverse-sapphire•4w ago
that should be fine, but now you will always have to work with arrays for those params, not sure how you had it setup with react router
nvm, just realized those are just the params that you expect to be arrays, this should be fine
wise-whiteOP•4w ago
Yes, it was always considered as an array, also with react router... Thank for the help here 🙏
adverse-sapphire•4w ago
about the
?
, tanstack router was adding it here:
https://github.com/TanStack/router/blob/22c9888857aca20cdffbf8f97927add139aaa5ea/packages/router-core/src/searchParams.ts#L61
ig qs
returns it without and router expects it with, so should be fine
you might want to check if the result of qs.stringify
is truthy, like they do, to avoid adding just the ?
to the urlwise-whiteOP•4w ago
Oh right. makes sense.. I will add that. 🙂
adverse-sapphire•4w ago
You might also be able to hint it to qs that it is supposed to be parsed as an array, but you need to get your route schema in the parser somehow, which I am not sure if it is possible
https://www.npmjs.com/package/query-string#types
found this option
genetic-orange•4w ago
about migration, you might also just use a url rewrite
genetic-orange•4w ago
Manuel Schiller (@schanuelmiller)
Soon in TanStack Router/Start: URL rewrites
This opens up a ton of possibilities such as
- i18n with translated URL paths
- multi-tenant apps with subdomains

X
genetic-orange•4w ago
to convert "old" into "new"
wise-whiteOP•4w ago
I will look into that one 🙂 Thanks.
Cool stuff. Do you have an estimate of when this will be available?
genetic-orange•4w ago
pretty soon
adverse-sapphire•2d ago
Hey, is there any news about when the feature will be released, or did I already miss the release?
genetic-orange•18h ago
yes it's released just not documented yet
adverse-sapphire•15h ago
nice, have you maybe an example?
genetic-orange•15h ago
GitHub
router/e2e/react-start/serialization-adapters at main · TanStack/r...
🤖 Fully typesafe Router for React (and friends) w/ built-in caching, 1st class search-param APIs, client-side cache integration and isomorphic rendering. - TanStack/router
adverse-sapphire•14h ago
hm? i see nothing about the rewrites
genetic-orange•14h ago
oh sorry
wrong example
here are some tests
genetic-orange•14h ago
GitHub
router/packages/react-router/tests/link.test.tsx at cc52bd792e50083...
🤖 Fully typesafe Router for React (and friends) w/ built-in caching, 1st class search-param APIs, client-side cache integration and isomorphic rendering. - TanStack/router
genetic-orange•14h ago
GitHub
router/packages/react-router/tests/router.test.tsx at cc52bd792e500...
🤖 Fully typesafe Router for React (and friends) w/ built-in caching, 1st class search-param APIs, client-side cache integration and isomorphic rendering. - TanStack/router
genetic-orange•14h ago
what do you want to do with rewrites?
adverse-sapphire•14h ago
multi tenant app with subdomains
genetic-orange•14h ago
ok so the link.test.tsx should help
if you need some more details, let me know
adverse-sapphire•11h ago
can i make the input/output async to fetch some data from the database?
here are some route examples:
carehaven.de
<- the root domain must be handle normal for api calls and something else
test1.carehaven.de/dashboard
-> /org/<id from test1 org>/dashboard
or maybe
test1.carehaven.de/dashboard
-> /org/dashboard
and the i make a middleware to fetch the orgId from subdomain and set it in to the router context or get it in beforeLoad on the route componentgenetic-orange•11h ago
no it cannot be async as we need it to be sync for link building
you need to perform those fetches outside of the rewrite
can you explain in more detail what you would need to fetch, and based on what?