# qk-serializable: Ensure All Key Parts Are JSON-Serializable ## Priority: CRITICAL ## Explanation Query keys are hashed using JSON serialization for cache lookups. Non-serializable values (functions, class instances, symbols, circular references) break caching and cause unexpected behavior. All parts of your query key must be JSON-serializable. ## Bad Example ```tsx // Functions are not serializable const { data } = useQuery({ queryKey: ['todos', () => 'active'], // Wrong: function in key queryFn: fetchTodos, }) // Class instances lose their prototype class Filter { constructor(public status: string) {} isActive() { return this.status === 'active' } } const filter = new Filter('active') const { data: todos } = useQuery({ queryKey: ['todos', filter], // Wrong: class instance queryFn: () => fetchTodos(filter), }) // Dates are technically serializable but become strings const { data: events } = useQuery({ queryKey: ['events', new Date()], // Problematic: new Date() each render queryFn: () => fetchEvents(date), }) // Symbols are not serializable const { data: settings } = useQuery({ queryKey: ['settings', Symbol('user')], // Wrong: symbol queryFn: fetchSettings, }) ``` ## Good Example ```tsx // Use primitive values and plain objects const { data } = useQuery({ queryKey: ['todos', 'active'], queryFn: fetchTodos, }) // Plain objects are fine const filters = { status: 'active', priority: 'high' } const { data: todos } = useQuery({ queryKey: ['todos', filters], queryFn: () => fetchTodos(filters), }) // For dates, use stable string representations const dateKey = date.toISOString().split('T')[0] // '2024-01-15' const { data: events } = useQuery({ queryKey: ['events', dateKey], queryFn: () => fetchEvents(date), }) // Arrays of primitives work correctly const { data: users } = useQuery({ queryKey: ['users', { ids: [1, 2, 3] }], queryFn: () => fetchUsers([1, 2, 3]), }) ``` ## Serializable Types **Safe to use:** - Strings, numbers, booleans, null - Plain objects (no prototype methods) - Arrays of serializable values - undefined (stripped but handled) **Avoid:** - Functions - Class instances - Symbols - Date objects (use ISO strings instead) - Map/Set (use arrays/objects instead) - Circular references ## Context - TanStack Query uses deterministic JSON hashing - Object property order doesn't matter: `{ a: 1, b: 2 }` equals `{ b: 2, a: 1 }` - Keys with `undefined` properties are normalized: `{ a: 1, b: undefined }` equals `{ a: 1 }` - Test serialization: `JSON.stringify(queryKey)` should work without errors