Capítulo 11 de 80

Chapter 11: Query Keys

Core Idea

Query keys are arrays that must be JSON-serializable and unique to the data they identify; TanStack Query hashes them deterministically (object key order doesn't matter, array item order does), and every value a queryFn reads must be reflected in the key or the cache and refetch behavior silently break.

Key Concepts

  • Shape: an array — from a single string (['todos']) up to string + serializable-object combinations (['todos', { status, page }]).
  • Simple keys: for generic list/index or non-hierarchical resources — ['todos'], ['something', 'special'].
  • Keys with variables: for hierarchical resources or parameterized queries — ['todo', 5], ['todo', 5, { preview: true }], ['todos', { type: 'done' }].
  • Deterministic hashing: object key order inside a key doesn't affect equality ({status, page} hashes the same as {page, status}); array item order does matter (['todos', status, page]['todos', page, status]).
  • The dependency rule: any variable your queryFn closes over that can change must be part of the queryKey — otherwise the cache can't tell requests apart and won't refetch when that variable changes. This is exactly what the ESLint plugin's exhaustive-deps rule enforces.

Code Examples

// Correct: todoId is a dependency, so it's in the key
function Todos({ todoId }) {
  const result = useQuery({
    queryKey: ['todos', todoId],
    queryFn: () => fetchTodoById(todoId),
  })
}
  • What it demonstrates: todoId closed over by queryFn also appears in queryKey — omitting it would make every todoId share one cache entry and never refetch on change.

Reference Tables

Key exampleUse case
['todos']Generic list/index resource
['todo', 5]Single hierarchical resource by id
['todo', 5, { preview: true }]Same resource, parameterized variant
['todos', { status, page }]List filtered/paginated by params

Key Takeaways

  1. Treat query keys as the dependency array of your query — anything the fetcher reads that can vary belongs in the key, exactly like useEffect's deps.
  2. Object property order inside a key segment doesn't matter for cache equality; array segment order does.
  3. Reach for a query-key-factory pattern (a small module exporting key-builder functions) once a codebase has more than a handful of related keys, to keep them consistent and centrally invalidable.

Connects To

  • Query Functions: queryKey is passed into the QueryFunctionContext.
  • Query Invalidation / Filters: partial key matching is what makes bulk invalidation by key prefix possible.
  • ESLint Plugin Query: exhaustive-deps enforces the dependency rule described here automatically.