EvanrobbyFrontend Developer
← All writing
Next.js · 5 min read

URL state without the mess

Search params are state. Treating them that way made filters shareable and the back button honest.

Source code on a dark screen
the address bar, doing its job

The car marketplace had eleven filters. The first version kept them in component state, which worked right up until someone tried to share a link to “automatic, under a million, Nairobi” and got the unfiltered homepage instead.

The URL is the source of truth

Once filters live in the search params, three things fall out for free: the link is shareable, the back button steps through filter changes, and a refresh keeps your place. The cost is a little parsing code and a firm rule that nothing else holds that state.

Parse once, at the edge of the component

I keep a tiny function that reads searchParams, runs them through a Zod schema with sensible defaults, and returns typed filters. Everything below that function trusts the result. Invalid values are dropped rather than thrown, because a bad link should still show a page.

If a screen can be reached by a link, its state belongs in the link.

Where it gets messy

Multi-select values, ranges and sort order all want their own encoding. Pick one convention early - I use comma-separated lists and min-max ranges - and write it down, because you will be reading those URLs in analytics for years.