Query Client
The query client is the central hub of @kitbag/query. It manages all your queries, handles caching, and provides the composables you'll use throughout your application.
Getting Started: Use the Default Client
For most applications, you should start with the default, ready-to-use client:
import { query, useQuery } from '@kitbag/query'
// Ready to use - comes pre-configured!
const userQuery = query('user', fetchUser)
const user = useQuery(userQuery, { params: [userId] })
Recommended Approach: The default client provides shared caching, unified query management, and enables powerful features like tag-based invalidation across your entire application. This is sufficient for 95% of use cases.
When to Create Your Own Client
Create a custom query client only when you need:
- Custom configuration for your entire app
- Multiple isolated contexts (e.g., different APIs with different caching strategies)
- Mutations and advanced features like
defineQuery
- Tag-based invalidation that should work across specific query groups
import { createQueryClient } from '@kitbag/query'
// Custom client with configuration
export const { query, useQuery, defineQuery, mutate } = createQueryClient({
defaultStaleTime: 5 * 60 * 1000, // 5 minutes
defaultCacheTime: 10 * 60 * 1000, // 10 minutes
defaultRetryCount: 3
})
Configuration Options
The query client accepts several configuration options:
Caching Options
- defaultStaleTime: How long data is considered fresh (default: 0)
- defaultCacheTime: How long unused data stays in cache (default: 5 minutes)
const { query, useQuery } = createQueryClient({
defaultStaleTime: 2 * 60 * 1000, // Data is fresh for 2 minutes
defaultCacheTime: 10 * 60 * 1000 // Keep in cache for 10 minutes
})
Retry Options
- defaultRetryCount: Number of retry attempts on failure (default: 3)
- defaultRetryDelay: Delay between retries (default: exponential backoff)
const { query, useQuery } = createQueryClient({
defaultRetryCount: 5,
defaultRetryDelay: (attempt) => Math.min(1000 * 2 ** attempt, 30000)
})
What You Get
The createQueryClient()
function returns an object with two main properties:
query
A function for creating query definitions. This is where you define your data fetching logic:
const userQuery = query('user', async (id: number) => {
const response = await fetch(`/api/users/${id}`)
return response.json()
})
useQuery
A Vue composable for using queries in your components:
const user = useQuery(userQuery, {
params: [userId]
})
Multiple Query Clients
You can create multiple query clients for different purposes:
// Main application data
export const { query: appQuery, useQuery: useAppQuery } = createQueryClient({
defaultStaleTime: 5 * 60 * 1000
})
// Real-time data with shorter cache times
export const { query: realtimeQuery, useQuery: useRealtimeQuery } = createQueryClient({
defaultStaleTime: 10 * 1000,
defaultCacheTime: 30 * 1000
})
Default vs Custom vs Multiple Clients
Default Client (Recommended for Most Apps)
Start here - use the default client that comes pre-configured:
// queries/users.ts
import { query, useQuery } from '@kitbag/query'
export const userQuery = query('user', fetchUser)
// components/UserProfile.vue
import { useQuery } from '@kitbag/query'
import { userQuery } from '../queries/users'
const user = useQuery(userQuery, { params: [userId] })
Benefits:
- Zero configuration - works out of the box
- Shared caching across your entire app
- Tag-based invalidation works globally
- Perfect for single-domain applications
Custom Global Client
Create your own client when you need app-wide configuration or mutations:
// queryClient.ts
import { createQueryClient } from '@kitbag/query'
export const { query, useQuery, defineQuery, mutate } = createQueryClient({
defaultStaleTime: 5 * 60 * 1000
})
Use when you need:
- Custom default settings for your app
- Mutations and advanced query patterns
defineQuery
for pre-configured API layers- Fine-tuned caching strategies
Multiple Clients (Advanced)
Create separate clients for different contexts or APIs:
// Main app data
export const { query: appQuery, useQuery: useAppQuery } = createQueryClient({
defaultStaleTime: 5 * 60 * 1000
})
// Real-time data with shorter cache times
export const { query: realtimeQuery, useQuery: useRealtimeQuery } = createQueryClient({
defaultStaleTime: 10 * 1000,
defaultCacheTime: 30 * 1000
})
Use when you have:
- Multiple APIs with different caching needs
- Isolated data contexts that shouldn't share cache
- Different authentication or configuration requirements
Best Practices
1. Start with the Default Client
Begin with the default client for simplicity:
// ✅ Best - Use the default client for most apps
import { query, useQuery } from '@kitbag/query'
export const userQuery = query('user', fetchUser)
2. Create Custom Client When Needed
Only create your own client when you need specific features:
// ✅ Good - Custom client when you need mutations or defineQuery
export const { query, useQuery, defineQuery, mutate } = createQueryClient({
defaultStaleTime: 5 * 60 * 1000
})
3. Configure Sensible Defaults
When you do create a custom client, set defaults that work for most of your queries:
// ✅ Good - Sensible defaults
const { query, useQuery } = createQueryClient({
defaultStaleTime: 2 * 60 * 1000, // 2 minutes is often good
defaultCacheTime: 10 * 60 * 1000, // Keep cache for 10 minutes
defaultRetryCount: 3 // Retry 3 times on failure
})
4. Override Per Query When Needed
Use query-specific options for special cases:
// Real-time data - shorter stale time
const liveDataQuery = query('live-data', fetcher, {
staleTime: 5000 // 5 seconds
})
// Static data - longer stale time
const configQuery = query('config', fetcher, {
staleTime: 60 * 60 * 1000 // 1 hour
})
Next Steps
Now that you understand the query client, learn about:
- Queries - Define your data fetching logic
- Mutations - Handle data modifications
- Tags & Invalidation - Manage cache invalidation