You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: src/blog/search-params-are-state.md
+13-13Lines changed: 13 additions & 13 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -7,9 +7,9 @@ authors:
7
7
8
8

9
9
10
-
## Search Params Are State . Treat Them That Way
10
+
## Search Params Are State . Treat Them That Way
11
11
12
-
Search params have been historically treated like second-class state. They're global, serializable, and shareable . but in most apps, they’re still hacked together with string parsing, loose conventions, and brittle utils.
12
+
Search params have been historically treated like second-class state. They're global, serializable, and shareable . but in most apps, they’re still hacked together with string parsing, loose conventions, and brittle utils.
13
13
14
14
Even something simple, like validating a `sort` param, quickly turns verbose:
15
15
@@ -30,7 +30,7 @@ This works, but it’s manual and repetitive. There’s no inference, no connect
30
30
31
31
Even worse, `URLSearchParams` is string-only. It doesn’t support nested JSON, arrays (beyond naive comma-splitting), or type coercion. So unless your state is flat and simple, you’re going to hit walls fast.
32
32
33
-
That’s why we’re starting to see a rise in tools and proposals . things like Nuqs, Next.js RFCs, and userland patterns . aimed at making search params more type-safe and ergonomic. Most of these focus on improving _reading_ from the URL.
33
+
That’s why we’re starting to see a rise in tools and proposals . things like Nuqs, Next.js RFCs, and userland patterns . aimed at making search params more type-safe and ergonomic. Most of these focus on improving _reading_ from the URL.
34
34
35
35
But almost none of them solve the deeper, harder problem: **writing** search params, safely and atomically, with full awareness of routing context.
36
36
@@ -56,15 +56,15 @@ Constraint is what makes coordination possible. It’s what allows **non-local c
56
56
57
57
---
58
58
59
-
### Local Abstractions Can Help . But They Don’t Coordinate
59
+
### Local Abstractions Can Help . But They Don’t Coordinate
60
60
61
-
Tools like **Nuqs** are a great example of how local abstractions can improve the _ergonomics_ of search param handling. You get Zod-powered parsing, type inference, even writable APIs . all scoped to a specific component or hook.
61
+
Tools like **Nuqs** are a great example of how local abstractions can improve the _ergonomics_ of search param handling. You get Zod-powered parsing, type inference, even writable APIs . all scoped to a specific component or hook.
62
62
63
-
They make it easier to read and write search params **in isolation** . and that’s valuable.
63
+
They make it easier to read and write search params **in isolation** . and that’s valuable.
64
64
65
65
But they don’t solve the broader issue of **coordination**. You still end up with duplicated schemas, disjointed expectations, and no way to enforce consistency between routes or components. Defaults can conflict. Types can drift. And when routes evolve, nothing guarantees all the callers update with them.
66
66
67
-
That’s the real fragmentation problem . and fixing it requires bringing search param schemas into the routing layer itself.
67
+
That’s the real fragmentation problem . and fixing it requires bringing search param schemas into the routing layer itself.
68
68
69
69
---
70
70
@@ -100,13 +100,13 @@ navigate({
100
100
})
101
101
```
102
102
103
-
It’s reducer-style, transactional, and integrates directly with the router’s reactivity model. Components only re-render when the specific search param they use changes . not every time the URL mutates.
103
+
It’s reducer-style, transactional, and integrates directly with the router’s reactivity model. Components only re-render when the specific search param they use changes . not every time the URL mutates.
104
104
105
105
---
106
106
107
107
### How TanStack Router Prevents Schema Fragmentation
108
108
109
-
When your search param logic lives in userland . scattered across hooks, utils, and helpers . it’s only a matter of time before you end up with **conflicting schemas**.
109
+
When your search param logic lives in userland . scattered across hooks, utils, and helpers . it’s only a matter of time before you end up with **conflicting schemas**.
110
110
111
111
Maybe one component expects \`sort: 'asc' | 'desc'\`. Another adds a \`filter\`. A third assumes \`sort: 'desc'\` by default. None of them share a source of truth.
112
112
@@ -117,7 +117,7 @@ This leads to:
117
117
- Navigation that sets values others can’t parse
118
118
- Broken deep linking and bugs you can’t trace
119
119
120
-
TanStack Router prevents this by tying schemas directly to your route definitions . **hierarchically**.
120
+
TanStack Router prevents this by tying schemas directly to your route definitions . **hierarchically**.
121
121
122
122
Parent routes can define shared search param validation. Child routes inherit that context, add to it, or extend it in type-safe ways. This makes it _impossible_ to accidentally create overlapping, incompatible schemas in different parts of your app.
123
123
@@ -160,23 +160,23 @@ validateSearch: z.object({
160
160
})
161
161
```
162
162
163
-
This kind of enforcement makes nested routes composable _and_ safe . a rare combo.
163
+
This kind of enforcement makes nested routes composable _and_ safe . a rare combo.
164
164
165
165
---
166
166
167
167
### Built-In Discipline
168
168
169
169
The magic here is that you don’t need to teach your team to follow conventions. The route _owns_ the schema. Everyone just uses it. There’s no duplication. No drift. No silent bugs. No guessing.
170
170
171
-
When you bring validation, typing, and ownership into the router itself, you stop treating URLs like strings and start treating them like real state . because that’s what they are.
171
+
When you bring validation, typing, and ownership into the router itself, you stop treating URLs like strings and start treating them like real state . because that’s what they are.
172
172
173
173
---
174
174
175
175
### Search Params Are State
176
176
177
177
Most routing systems treat search params like an afterthought. Something you _can_ read, maybe parse, maybe stringify, but rarely something you can actually **trust**.
178
178
179
-
TanStack Router flips that on its head. It makes search params a core part of the routing contract . validated, inferable, writable, and reactive.
179
+
TanStack Router flips that on its head. It makes search params a core part of the routing contract . validated, inferable, writable, and reactive.
180
180
181
181
Because if you’re not treating search params like state, you’re going to keep leaking it, breaking it, and working around it.
0 commit comments