The framework agnostic core that powers TanStack Query for data fetching and caching
npx @tessl/cli install tessl/npm-tanstack--query-core@5.86.0TanStack Query Core is the framework-agnostic foundation that powers TanStack Query, providing sophisticated data fetching, caching, synchronization, and server state management. It implements intelligent caching strategies, automatic background updates, optimistic updates, and handles complex scenarios like query deduplication, infinite queries, and mutation management.
npm install @tanstack/query-coreimport { QueryClient, QueryCache, MutationCache } from "@tanstack/query-core";For CommonJS:
const { QueryClient, QueryCache, MutationCache } = require("@tanstack/query-core");import { QueryClient, QueryObserver } from "@tanstack/query-core";
// Create a client
const queryClient = new QueryClient();
// Create and use a query observer
const observer = new QueryObserver(queryClient, {
queryKey: ['user', 123],
queryFn: async () => {
const response = await fetch('/api/user/123');
return response.json();
},
});
// Subscribe to results
const unsubscribe = observer.subscribe((result) => {
console.log(result.data); // User data
console.log(result.isLoading); // Loading state
console.log(result.error); // Error state
});
// Cleanup
unsubscribe();TanStack Query Core is built around several key architectural components:
QueryCache and MutationCache systems providing intelligent storage and retrievalQueryObserver, InfiniteQueryObserver, and MutationObserver classes for reactive state managementfocusManager, onlineManager, and notifyManager for handling browser events and notification batchingQuery and Mutation classes managing individual request lifecyclesCentral client for orchestrating all query and mutation operations with intelligent defaults, caching strategies, and lifecycle management.
class QueryClient {
constructor(config?: QueryClientConfig);
mount(): void;
unmount(): void;
getQueryCache(): QueryCache;
getMutationCache(): MutationCache;
}
interface QueryClientConfig {
queryCache?: QueryCache;
mutationCache?: MutationCache;
defaultOptions?: DefaultOptions;
}Core query functionality including data fetching, caching, invalidation, and state management with automatic background updates.
fetchQuery<T>(options: FetchQueryOptions<T>): Promise<T>;
prefetchQuery<T>(options: FetchQueryOptions<T>): Promise<void>;
getQueryData<T>(queryKey: QueryKey): T | undefined;
setQueryData<T>(queryKey: QueryKey, updater: Updater<T>, options?: SetDataOptions): T | undefined;
invalidateQueries(filters?: InvalidateQueryFilters, options?: InvalidateOptions): Promise<void>;
interface FetchQueryOptions<T> {
queryKey: QueryKey;
queryFn: QueryFunction<T>;
staleTime?: number;
gcTime?: number;
}Reactive observers for tracking query state changes with automatic updates, optimistic results, and lifecycle management.
class QueryObserver<T> {
constructor(client: QueryClient, options: QueryObserverOptions<T>);
getCurrentResult(): QueryObserverResult<T>;
subscribe(onStoreChange: (result: QueryObserverResult<T>) => void): () => void;
refetch(options?: RefetchOptions): Promise<QueryObserverResult<T>>;
}
interface QueryObserverResult<T> {
data: T | undefined;
error: Error | null;
isLoading: boolean;
isFetching: boolean;
isSuccess: boolean;
isError: boolean;
status: 'pending' | 'error' | 'success';
}Specialized functionality for paginated data with automatic page management, bi-directional fetching, and cursor-based pagination.
class InfiniteQueryObserver<T> extends QueryObserver<InfiniteData<T>> {
fetchNextPage(options?: FetchNextPageOptions): Promise<InfiniteQueryObserverResult<T>>;
fetchPreviousPage(options?: FetchPreviousPageOptions): Promise<InfiniteQueryObserverResult<T>>;
}
interface InfiniteData<T> {
pages: T[];
pageParams: unknown[];
}
interface InfiniteQueryObserverResult<T> extends QueryObserverResult<InfiniteData<T>> {
hasNextPage: boolean;
hasPreviousPage: boolean;
isFetchingNextPage: boolean;
isFetchingPreviousPage: boolean;
}Mutation management for data modifications with optimistic updates, rollback capabilities, and side effect handling.
class MutationObserver<T, TVariables> {
constructor(client: QueryClient, options: MutationObserverOptions<T, TVariables>);
mutate(variables: TVariables, options?: MutateOptions<T, TVariables>): Promise<T>;
reset(): void;
getCurrentResult(): MutationObserverResult<T>;
}
interface MutationObserverResult<T> {
data: T | undefined;
error: Error | null;
isIdle: boolean;
isPending: boolean;
isSuccess: boolean;
isError: boolean;
status: 'idle' | 'pending' | 'success' | 'error';
}Low-level cache operations for direct query and mutation cache manipulation with events, filtering, and batch operations.
class QueryCache {
constructor(config?: QueryCacheConfig);
find<T>(filters: QueryFilters): Query<T> | undefined;
findAll(filters?: QueryFilters): Array<Query>;
clear(): void;
subscribe(callback: (event: QueryCacheNotifyEvent) => void): () => void;
}
interface QueryFilters {
queryKey?: QueryKey;
exact?: boolean;
stale?: boolean;
active?: boolean;
inactive?: boolean;
}Server-side rendering support with serialization and deserialization of client state for hydration across client-server boundaries.
function dehydrate(client: QueryClient, options?: DehydrateOptions): DehydratedState;
function hydrate(client: QueryClient, dehydratedState: unknown, options?: HydrateOptions): void;
interface DehydratedState {
mutations: Array<DehydratedMutation>;
queries: Array<DehydratedQuery>;
}Browser event management for automatic refetching on focus and network reconnection with customizable event handling.
const focusManager: {
setEventListener(setup: SetupFn): void;
setFocused(focused?: boolean): void;
isFocused(): boolean;
};
const onlineManager: {
setEventListener(setup: SetupFn): void;
setOnline(online: boolean): void;
isOnline(): boolean;
};Core utility functions for key hashing, data manipulation, query matching, and functional programming patterns.
function hashKey(key: QueryKey): string;
function matchQuery(filters: QueryFilters, query: Query): boolean;
function replaceEqualDeep<T>(a: unknown, b: T): T;
const keepPreviousData: <T>(previousData: T) => T;
const skipToken: Symbol;Direct access to the underlying Query and Mutation class instances for advanced use cases.
class Query<TQueryFnData, TError, TData, TQueryKey extends QueryKey> {
queryKey: TQueryKey;
queryHash: string;
state: QueryState<TData, TError>;
setData(data: TData): void;
setState(state: Partial<QueryState<TData, TError>>): void;
}
class Mutation<TData, TError, TVariables, TContext> {
mutationId: number;
state: MutationState<TData, TError, TVariables, TContext>;
setData(data: TData): void;
setState(state: Partial<MutationState<TData, TError, TVariables, TContext>>): void;
}Experimental functionality that may change in future versions.
function experimental_streamedQuery<
TQueryFnData = unknown,
TData = Array<TQueryFnData>,
TQueryKey extends QueryKey = QueryKey
>(params: StreamedQueryParams<TQueryFnData, TData, TQueryKey>): QueryFunction<TData, TQueryKey>;
type StreamedQueryParams<TQueryFnData, TData, TQueryKey extends QueryKey> =
| SimpleStreamedQueryParams<TQueryFnData, TQueryKey>
| ReducibleStreamedQueryParams<TQueryFnData, TData, TQueryKey>;
interface SimpleStreamedQueryParams<TQueryFnData, TQueryKey extends QueryKey> {
streamFn: (context: QueryFunctionContext<TQueryKey>) => AsyncIterable<TQueryFnData> | Promise<AsyncIterable<TQueryFnData>>;
refetchMode?: 'append' | 'reset' | 'replace';
}
interface ReducibleStreamedQueryParams<TQueryFnData, TData, TQueryKey extends QueryKey> {
streamFn: (context: QueryFunctionContext<TQueryKey>) => AsyncIterable<TQueryFnData> | Promise<AsyncIterable<TQueryFnData>>;
refetchMode?: 'append' | 'reset' | 'replace';
reducer: (acc: TData, chunk: TQueryFnData) => TData;
initialValue: TData;
}// QueryKey with module augmentation support
type QueryKey = Register extends {
queryKey: infer TQueryKey
}
? TQueryKey extends ReadonlyArray<unknown>
? TQueryKey
: TQueryKey extends Array<unknown>
? TQueryKey
: ReadonlyArray<unknown>
: ReadonlyArray<unknown>;
// QueryFunction with pagination support
type QueryFunction<
T = unknown,
TQueryKey extends QueryKey = QueryKey,
TPageParam = never
> = (context: QueryFunctionContext<TQueryKey, TPageParam>) => T | Promise<T>;
// Complete QueryFunctionContext with all properties
type QueryFunctionContext<
TQueryKey extends QueryKey = QueryKey,
TPageParam = never
> = [TPageParam] extends [never]
? {
client: QueryClient;
queryKey: TQueryKey;
signal: AbortSignal;
meta: QueryMeta | undefined;
pageParam?: unknown;
direction?: unknown; // @deprecated
}
: {
client: QueryClient;
queryKey: TQueryKey;
signal: AbortSignal;
pageParam: TPageParam;
direction: FetchDirection; // @deprecated
meta: QueryMeta | undefined;
};
type QueryStatus = 'pending' | 'error' | 'success';
type FetchStatus = 'fetching' | 'paused' | 'idle';
type MutationStatus = 'idle' | 'pending' | 'success' | 'error';
// Complete DefaultOptions interface
interface DefaultOptions<TError = DefaultError> {
queries?: OmitKeyof<QueryObserverOptions<unknown, TError>, 'suspense' | 'queryKey'>;
mutations?: MutationObserverOptions<unknown, TError, unknown, unknown>;
hydrate?: HydrateOptions['defaultOptions'];
dehydrate?: DehydrateOptions;
}
type Updater<T> = T | ((old: T) => T);
// Module augmentation interface
interface Register {
// Empty by default, can be augmented by users
}
type DefaultError = Error;
type FetchDirection = 'forward' | 'backward';
type QueryMeta = Record<string, unknown>;