install
source · Clone the upstream repo
git clone https://github.com/Intense-Visions/harness-engineering
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/Intense-Visions/harness-engineering "$T" && mkdir -p ~/.claude/skills && cp -r "$T/agents/skills/claude-code/tanstack-dependent-queries" ~/.claude/skills/intense-visions-harness-engineering-tanstack-dependent-queries-c708d2 && rm -rf "$T"
manifest:
agents/skills/claude-code/tanstack-dependent-queries/SKILL.mdsource content
TanStack Query: Dependent Queries
Chain queries that depend on each other's results using the enabled flag and useQueries
When to Use
- Fetching data that depends on the result of a previous query (e.g., user ID needed before fetching user's posts)
- Running a set of queries in parallel when all inputs are known upfront
- Conditionally fetching based on component state or user interaction
- Fetching a dynamic list of resources in parallel (N queries for N items)
Instructions
- Use the
option to block a query from running until its prerequisite data is available.enabled - Pass the prerequisite value directly into
— falsy values (enabled
,undefined
,null
,false
) disable the query.0 - Include the prerequisite value in the query key so the query re-runs when it changes.
- Use
to run a dynamic list of queries in parallel — pass an array of query option objects.useQueries() - Do not chain more than two or three dependent queries — deep chains indicate a data model problem or an opportunity to join data server-side.
- Use
to transform query data before it becomes the input for a dependent query — keeps transformation logic in the query, not in the component.select
// Single dependent query — user's posts depend on user ID function useUserPosts(username: string) { // Step 1: fetch user by username const userQuery = useQuery({ queryKey: ['user', username], queryFn: () => fetchUser(username), }); // Step 2: fetch posts only after user is loaded const postsQuery = useQuery({ queryKey: ['posts', 'by-user', userQuery.data?.id], queryFn: () => fetchPostsByUser(userQuery.data!.id), enabled: !!userQuery.data?.id, // blocks until user.id is available }); return { user: userQuery.data, posts: postsQuery.data, isLoading: userQuery.isLoading || postsQuery.isLoading, }; } // Parallel queries for a dynamic list — fetch N items simultaneously function usePostDetails(postIds: string[]) { return useQueries({ queries: postIds.map((id) => ({ queryKey: ['posts', 'detail', id], queryFn: () => fetchPost(id), staleTime: 5 * 60 * 1000, })), }); // Returns QueryResult[] — one per ID } // Conditional fetch — only when a filter is active function useFilteredPosts(filter: string | null) { return useQuery({ queryKey: ['posts', 'filtered', filter], queryFn: () => fetchFilteredPosts(filter!), enabled: filter !== null && filter.length > 0, }); }
Details
TanStack Query executes all queries concurrently by default — each
useQuery call starts a fetch immediately when the component mounts. Dependent queries introduce explicit sequencing.
flag behavior: When enabled
enabled is false, the query is in pending status with fetchStatus: 'idle' — it has no data and is not fetching. As soon as enabled becomes true (e.g., after the prerequisite query resolves), TanStack Query fetches immediately.
Loading state propagation: A dependent query chain means loading states are sequential — the second query cannot start until the first resolves. The combined loading time is the sum of all fetches, not the max. Evaluate whether the dependency is real (data genuinely needed) or whether a backend endpoint could join the data.
for dynamic lists: useQueries
useQueries is the correct API for N dynamic queries. Calling useQuery in a loop violates React's rules of hooks (cannot be inside a conditional or loop). useQueries handles variable-length arrays of query definitions.
for derived keys: Use select
select to transform query data before passing it to a dependent query key:
const userId = useQuery({ queryKey: ['auth'], queryFn: fetchCurrentUser, select: (user) => user.id, // only re-triggers when ID changes, not whole user object });
The
select function memoizes — dependents only re-render when the selected value changes.
Avoiding waterfalls: On the server side (Next.js Server Components), fetch data in parallel with
Promise.all instead of sequential awaits. Client-side dependency chains are sometimes unavoidable (auth token → user data), but server-side waterfalls are always avoidable.
Source
https://tanstack.com/query/latest/docs/framework/react/guides/dependent-queries
Process
- Read the instructions and examples in this document.
- Apply the patterns to your implementation, adapting to your specific context.
- Verify your implementation against the details and edge cases listed above.
Harness Integration
- Type: knowledge — this skill is a reference document, not a procedural workflow.
- No tools or state — consumed as context by other skills and agents.
Success Criteria
- The patterns described in this document are applied correctly in the implementation.
- Edge cases and anti-patterns listed in this document are avoided.