When you build an editor like Zed, your components constantly need data that arrives asynchronously: language-server responses, file listings, collaborator presence, telemetry. The GPUI render loop is synchronous, which means juggling in-flight requests, caches, retries, and stale data by hand gets old fast.
gpui-query adapts TanStack Query's proven model to Rust and GPUI. It keeps the ideas you already know — declarative queries, automatic caching, background refetching, cooperative cancellation — and grounds them in Rust's type system and GPUI's reactive primitives.
Three layers, one crate
The crate is split into layers so you can adopt only what you need:
core— a Serde-only state machine (QueryResource,CachePolicy,RetryPolicy,QuerySignal). Framework-agnostic and serializable.client— the GPUIQueryClientregistry, with type-partitioned buckets for resource lifecycle, garbage collection, and persistence.hook— the ergonomicuse_query/use_mutationhooks that components subscribe through.
A query in five lines
use gpui_query::hook::use_query;
use gpui_query::{CachePolicy, QueryKey, RequestPolicy};
let (users, _subscription) = use_query(
QueryKey::from(["users"]),
CachePolicy::Ttl { ttl_ms: 60_000 },
RequestPolicy::LatestWins,
|| async {
let resp = reqwest::get("/api/users").await?;
let users: Vec<User> = resp.json().await?;
Ok(users)
},
cx,
);use_query returns a tuple (data, status) by Rust convention — ergonomic to destructure, with the status enum carrying the full lifecycle state. You never write useEffect glue or manage a loading boolean by hand.
What you get for free
- Caching via
CachePolicy(NoCache,Ttl,StaleWhileRevalidate). - Retries with fixed delays or exponential backoff and a cap.
- Cooperative cancellation through
QuerySignal(Arc<AtomicBool>) so a component unmounting does not leak work. - Persistence via the
QueryPersistertrait — serialize and restore cache state across sessions. - Infinite queries for paginated data, with bidirectional fetching.
Who is this for?
If you are building anything nontrivial on GPUI and find yourself re-implementing a cache, a refetch timer, or a cancellation token, gpui-query exists for you. The core layer is testable in isolation; the hook layer slots straight into your views. Give it a try and open an issue if anything feels off.