Skip to main content
Query filters allow you to target specific queries when performing batch operations like invalidation, refetching, or removal. The filters API provides powerful and flexible query matching.

Filter Properties

The QueryFilters interface supports the following properties:
interface QueryFilters {
  /**
   * Filter to active queries, inactive queries or all queries
   */
  type?: 'active' | 'inactive' | 'all'
  
  /**
   * Match query key exactly
   */
  exact?: boolean
  
  /**
   * Include queries matching this predicate function
   */
  predicate?: (query: Query) => boolean
  
  /**
   * Include queries matching this query key
   */
  queryKey?: QueryKey
  
  /**
   * Include or exclude stale queries
   */
  stale?: boolean
  
  /**
   * Include queries matching their fetchStatus
   */
  fetchStatus?: 'fetching' | 'paused' | 'idle'
}
Source: packages/query-core/src/utils.ts:30

Query Key Filtering

Filter by query key with partial or exact matching:
import { useQueryClient } from '@tanstack/react-query'

function Component() {
  const queryClient = useQueryClient()

  // Invalidate all queries with keys starting with 'todos'
  queryClient.invalidateQueries({
    queryKey: ['todos']
  })

  // Matches:
  // ['todos']
  // ['todos', 1]
  // ['todos', { status: 'active' }]
  // ['todos', 1, 'comments']
}
By default, query key filtering uses partial matching. A query matches if the filter key is a prefix of the query’s key.

Exact Matching

Use exact: true to match only queries with the exact key:
import { useQueryClient } from '@tanstack/react-query'

function Component() {
  const queryClient = useQueryClient()

  // Only invalidate the exact query ['todos', 1]
  queryClient.invalidateQueries({
    queryKey: ['todos', 1],
    exact: true
  })

  // Matches:
  // ['todos', 1] ✅
  
  // Does not match:
  // ['todos'] ❌
  // ['todos', 1, 'comments'] ❌
  // ['todos', 2] ❌
}

Type Filtering

Filter by query activity status:
import { useQueryClient } from '@tanstack/react-query'

function Component() {
  const queryClient = useQueryClient()

  // Refetch only active queries
  queryClient.refetchQueries({
    type: 'active'
  })

  // Refetch only inactive queries
  queryClient.refetchQueries({
    type: 'inactive'
  })

  // Refetch all queries (active and inactive)
  queryClient.refetchQueries({
    type: 'all'
  })
}
1

Active queries

Queries with one or more active observers (mounted components)
2

Inactive queries

Queries in the cache with no active observers
3

All queries

Both active and inactive queries

Stale Filtering

Filter by staleness:
import { useQueryClient } from '@tanstack/react-query'

function Component() {
  const queryClient = useQueryClient()

  // Refetch only stale queries
  queryClient.refetchQueries({
    stale: true
  })

  // Refetch only fresh queries
  queryClient.refetchQueries({
    stale: false
  })
}

Fetch Status Filtering

Filter by fetch status:
import { useQueryClient } from '@tanstack/react-query'

function Component() {
  const queryClient = useQueryClient()

  // Get all currently fetching queries
  const fetchingQueries = queryClient.isFetching({
    fetchStatus: 'fetching'
  })

  // Count idle queries
  const idleCount = queryClient.getQueryCache().findAll({
    fetchStatus: 'idle'
  }).length
}

Predicate Filtering

Use custom logic to filter queries:
import { useQueryClient } from '@tanstack/react-query'

function Component() {
  const queryClient = useQueryClient()

  // Invalidate queries with errors
  queryClient.invalidateQueries({
    predicate: (query) => query.state.status === 'error'
  })

  // Remove queries older than 1 hour
  queryClient.removeQueries({
    predicate: (query) => {
      const oneHourAgo = Date.now() - 60 * 60 * 1000
      return query.state.dataUpdatedAt < oneHourAgo
    }
  })

  // Refetch queries with specific meta
  queryClient.refetchQueries({
    predicate: (query) => query.meta?.refetchOnDemand === true
  })
}
Predicate functions receive the full Query instance, giving you access to state, options, and meta.

Combining Filters

Combine multiple filter properties:
import { useQueryClient } from '@tanstack/react-query'

function Component() {
  const queryClient = useQueryClient()

  // Refetch active, stale 'todos' queries
  queryClient.refetchQueries({
    queryKey: ['todos'],
    type: 'active',
    stale: true
  })

  // Remove inactive, stale queries with errors
  queryClient.removeQueries({
    type: 'inactive',
    stale: true,
    predicate: (query) => query.state.status === 'error'
  })
}

Using Filters with invalidateQueries

Invalidate specific queries:
import { useQueryClient } from '@tanstack/react-query'
import { useMutation } from '@tanstack/react-query'

function TodoForm() {
  const queryClient = useQueryClient()

  const mutation = useMutation({
    mutationFn: createTodo,
    onSuccess: () => {
      // Invalidate all 'todos' queries
      queryClient.invalidateQueries({
        queryKey: ['todos']
      })
      
      // Invalidate exact query
      queryClient.invalidateQueries({
        queryKey: ['todos', 'list'],
        exact: true
      })
    }
  })

  return <form onSubmit={mutation.mutate}>...</form>
}
Source: packages/query-core/src/queryClient.ts:294

Using Filters with refetchQueries

Refetch matching queries:
import { useQueryClient } from '@tanstack/react-query'

function RefreshButton() {
  const queryClient = useQueryClient()

  const handleRefresh = async () => {
    // Refetch all active queries
    await queryClient.refetchQueries({
      type: 'active'
    })

    // Refetch only stale, active queries
    await queryClient.refetchQueries({
      type: 'active',
      stale: true
    })
  }

  return <button onClick={handleRefresh}>Refresh</button>
}
Source: packages/query-core/src/queryClient.ts:316

Using Filters with removeQueries

Remove queries from the cache:
import { useQueryClient } from '@tanstack/react-query'

function CacheCleaner() {
  const queryClient = useQueryClient()

  const clearErroredQueries = () => {
    queryClient.removeQueries({
      predicate: (query) => query.state.status === 'error'
    })
  }

  const clearOldQueries = () => {
    const oneWeekAgo = Date.now() - 7 * 24 * 60 * 60 * 1000
    queryClient.removeQueries({
      predicate: (query) => query.state.dataUpdatedAt < oneWeekAgo
    })
  }

  return (
    <div>
      <button onClick={clearErroredQueries}>Clear Errors</button>
      <button onClick={clearOldQueries}>Clear Old Data</button>
    </div>
  )
}
Source: packages/query-core/src/queryClient.ts:271

Finding Queries

Find queries in the cache using filters:
import { useQueryClient } from '@tanstack/react-query'

function CacheInspector() {
  const queryClient = useQueryClient()

  // Find all matching queries
  const todoQueries = queryClient.getQueryCache().findAll({
    queryKey: ['todos']
  })

  // Find exact query
  const specificQuery = queryClient.getQueryCache().find({
    queryKey: ['todos', 1],
    exact: true
  })

  // Count fetching queries
  const fetchingCount = queryClient.getQueryCache().findAll({
    fetchStatus: 'fetching'
  }).length

  return (
    <div>
      <p>Todo queries: {todoQueries.length}</p>
      <p>Currently fetching: {fetchingCount}</p>
    </div>
  )
}
Source: packages/query-core/src/queryCache.ts:193

isFetching with Filters

Count currently fetching queries:
import { useIsFetching } from '@tanstack/react-query'

function GlobalLoader() {
  // Count all fetching queries
  const isFetching = useIsFetching()

  // Count fetching 'todos' queries
  const isFetchingTodos = useIsFetching({
    queryKey: ['todos']
  })

  // Count fetching queries with predicate
  const isFetchingImportant = useIsFetching({
    predicate: (query) => query.meta?.priority === 'high'
  })

  if (isFetching === 0) return null

  return <div>Loading {isFetching} queries...</div>
}
Source: packages/query-core/src/queryClient.ts:109

Mutation Filters

Similar filtering for mutations:
interface MutationFilters {
  /**
   * Match mutation key exactly
   */
  exact?: boolean
  
  /**
   * Include mutations matching this predicate function
   */
  predicate?: (mutation: Mutation) => boolean
  
  /**
   * Include mutations matching this mutation key
   */
  mutationKey?: MutationKey
  
  /**
   * Filter by mutation status
   */
  status?: 'idle' | 'pending' | 'success' | 'error'
}
Source: packages/query-core/src/utils.ts:57

Real-World Examples

Selective Cache Invalidation

import { useMutation, useQueryClient } from '@tanstack/react-query'

function useUpdateTodo() {
  const queryClient = useQueryClient()

  return useMutation({
    mutationFn: updateTodo,
    onSuccess: (updatedTodo) => {
      // Invalidate list queries
      queryClient.invalidateQueries({
        queryKey: ['todos', 'list']
      })

      // Invalidate the specific todo
      queryClient.invalidateQueries({
        queryKey: ['todos', updatedTodo.id],
        exact: true
      })

      // Invalidate related queries
      queryClient.invalidateQueries({
        predicate: (query) => 
          query.queryKey[0] === 'todos' &&
          query.queryKey[1] === 'project' &&
          query.queryKey[2] === updatedTodo.projectId
      })
    }
  })
}

Periodic Cache Cleanup

import { useEffect } from 'react'
import { useQueryClient } from '@tanstack/react-query'

function useCacheCleanup() {
  const queryClient = useQueryClient()

  useEffect(() => {
    const interval = setInterval(() => {
      // Remove errored queries older than 5 minutes
      const fiveMinutesAgo = Date.now() - 5 * 60 * 1000
      
      queryClient.removeQueries({
        predicate: (query) =>
          query.state.status === 'error' &&
          query.state.errorUpdatedAt < fiveMinutesAgo
      })
    }, 60 * 1000) // Run every minute

    return () => clearInterval(interval)
  }, [queryClient])
}

Smart Refresh

import { useQueryClient } from '@tanstack/react-query'

function useSmartRefresh() {
  const queryClient = useQueryClient()

  return async () => {
    // Only refetch active, stale queries
    await queryClient.refetchQueries({
      type: 'active',
      stale: true,
      predicate: (query) => {
        // Don't refetch queries with errors
        if (query.state.status === 'error') return false
        
        // Don't refetch if already fetching
        if (query.state.fetchStatus === 'fetching') return false
        
        return true
      }
    })
  }
}

Best Practices

  1. Be specific: Use exact matching when possible to avoid unintended invalidations
  2. Combine filters: Use multiple filter properties for precise targeting
  3. Use predicate sparingly: Predicate functions run on every query, so keep them efficient
  4. Consider type: Invalidating inactive queries may not trigger refetches
  5. Test filters: Verify your filters match the intended queries

See Also

Build docs developers (and LLMs) love