Skip to content

Add empty query detection and skipping#5130

Draft
captbaritone wants to merge 5 commits intofacebook:mainfrom
captbaritone:empty-query-check
Draft

Add empty query detection and skipping#5130
captbaritone wants to merge 5 commits intofacebook:mainfrom
captbaritone:empty-query-check

Conversation

@captbaritone
Copy link
Contributor

@captbaritone captbaritone commented Jan 7, 2026

Fixes #5126

Summary

Some queries, when invoked with a set of variables are conceptually "empty". Meaning we can prove before sending them to the server that they will fetch zero fields. Some examples include:

  1. A query where all top level fields have been skipped via @skip.
  2. All fields are either Relay resolvers with no server data in their rootFragment, or are client schema extensions

When using a fetch policy like store-or-network we're able to avoid fetching these fields since we find that all server fields can be fulfilled from the cache. However, even when a fetch policy tells us we MUST go to the network, or we are using an API which is designed to explicitly fetch irrespective of fetch policy, these queries can still be safely skipped.

This PR introduces a new check parallel to DataChecker called EmptyChecker which is light-weight and can be called more aggressively than DataChecker. It's faster to run because it does not look up any data in the store, and exits immediately as soon as it finds any server data. This means its time complexity should be on the order of O(top level fields).

@meta-cla meta-cla bot added the CLA Signed label Jan 7, 2026
Adds EmptyChecker to detect queries with no server-fetchable fields due to
@skip/@include directives or client-only fields. When enabled via the
ENABLE_EMPTY_QUERY_CHECK feature flag, empty queries are skipped and do not
result in network requests.

Key changes:
- New EmptyChecker module to traverse query AST and detect empty queries
- Add isEmpty() method to IEnvironment, IMultiActorEnvironment interfaces
- Skip execution in RelayModernEnvironment.execute() and executeWithSource()
- Update loadQuery to check isEmpty() before fetching
- Add 'execute.skipped' log event with reason: 'empty'
- Add comprehensive tests for EmptyChecker and React hooks integration
- Feature flag ENABLE_EMPTY_QUERY_CHECK (default: false)

Test plan:
- EmptyChecker-test.js: Tests all query AST node types and conditional logic
- useLazyLoadQueryNode-empty-query-test.js: Tests useLazyLoadQuery and
  usePreloadedQuery + loadQuery patterns with empty queries
Removes errant throw statement that was making the subsequent
return statement unreachable, fixing Flow typecheck CI failure.
- Sort imports alphabetically
- Remove unused renderFn variable
- Add clarifying comments for test assertions
Rename useLazyLoadQueryNode-empty-query-test.js to
emptyQueriesAvoidSuspense-test.js and update GraphQL query names.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

useLazyLoadQuery does not prevent sending empty requests to server when using store-and-network

1 participant