ADR 001: useFetch vs useAsyncData
Status: Accepted
Date: 2024-01-15
Context
Nuxt 3 provides two main composables for data fetching: useFetch and useAsyncData. When generating composables from OpenAPI specs, we need to decide which to use as the default pattern.
useFetch
typescript
const { data, pending, error } = useFetch('/api/pets/1')- Built-in URL handling
- Simpler API
- Automatic key generation
- Direct $fetch wrapper
useAsyncData
typescript
const { data, pending, error } = useAsyncData(
'pet-1',
() => $fetch('/api/pets/1')
)- Manual key specification
- More control over fetching
- Separate fetch function
- More flexible
Decision
Generate both useFetch* and useAsyncData* variants for GET requests.
For GET operations:
useFetchPet(id)- Default, recommendeduseAsyncDataPet(id)- When custom key needed
For POST/PUT/DELETE operations:
- Only
useFetch*withimmediate: false
Rationale
Why Both?
- Default Simplicity - Most users want simple
useFetch - Advanced Control - Some users need
useAsyncDatafeatures - Choice - Let developers choose based on needs
- No Breaking Changes - Supporting both means no forced migration
Why useFetch as Default?
- Simpler API - Fewer parameters needed
- Auto Key Generation - No manual key management
- Nuxt Recommended - Official docs recommend useFetch
- Better DX - Less boilerplate
Why Include useAsyncData?
- Custom Keys - When you need specific cache keys
- Shared Data - Multiple components sharing same data
- Advanced Patterns - Complex data transformation
- Migration - Users coming from Nuxt 2 patterns
Implementation
typescript
// Generated for each GET operation
export function useFetchPet(
id: MaybeRef<number>,
options?: UseFetchOptions<Pet>
) {
return useFetch<Pet>(
() => `/pets/${unref(id)}`,
options
)
}
export function useAsyncDataPet(
id: MaybeRef<number>,
options?: UseAsyncDataOptions<Pet>
) {
return useAsyncData(
() => `pet-${unref(id)}`,
() => $fetch<Pet>(`/pets/${unref(id)}`),
options
)
}Consequences
Positive
- Flexibility - Developers can choose what they need
- Better DX - Simpler default for common cases
- No Lock-In - Easy to switch between variants
- Complete - Covers all use cases
Negative
- More Code - Generator creates twice as many GET composables
- Documentation - Need to explain when to use each
- Choice Overload - Beginners might be confused
- Bundle Size - Slightly larger (mitigated by tree-shaking)
Alternatives Considered
Alternative 1: Only useFetch
Rejected - Some users need useAsyncData features like custom keys
Alternative 2: Only useAsyncData
Rejected - More verbose, harder for beginners
Alternative 3: Configuration Option
Rejected - Adds complexity, forces choice at generation time
Next Steps
- Document when to use each variant in guide
- Add examples for both patterns
- Consider CLI flag to skip one variant if needed
